[bigassfan] Null annotations (#13903)
* Null annotations and some refactoring * Fix synchronized block * Fix remaining warnings Signed-off-by: Leo Siepel <leosiepel@gmail.com>pull/14168/head
parent
b91fc94bdb
commit
cb460657eb
|
@ -12,26 +12,29 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.bigassfan.internal;
|
package org.openhab.binding.bigassfan.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link BigAssFanConfig} is responsible for storing the BigAssFan thing configuration.
|
* The {@link BigAssFanConfig} is responsible for storing the BigAssFan thing configuration.
|
||||||
*
|
*
|
||||||
* @author Mark Hilbush - Initial contribution
|
* @author Mark Hilbush - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class BigAssFanConfig {
|
public class BigAssFanConfig {
|
||||||
/**
|
/**
|
||||||
* Name of the device
|
* Name of the device
|
||||||
*/
|
*/
|
||||||
private String label;
|
private String label = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IP address of the device
|
* IP address of the device
|
||||||
*/
|
*/
|
||||||
private String ipAddress;
|
private String ipAddress = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MAC address of the device
|
* MAC address of the device
|
||||||
*/
|
*/
|
||||||
private String macAddress;
|
private String macAddress = "";
|
||||||
|
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
|
@ -58,16 +61,7 @@ public class BigAssFanConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
if (label == null || label.isBlank()) {
|
return !label.isBlank() && !ipAddress.isBlank() && !macAddress.isBlank();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ipAddress == null || ipAddress.isBlank()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (macAddress == null || macAddress.isBlank()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -12,41 +12,44 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.bigassfan.internal.discovery;
|
package org.openhab.binding.bigassfan.internal.discovery;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link BigAssFanDevice} is responsible for storing information about a fan.
|
* The {@link BigAssFanDevice} is responsible for storing information about a fan.
|
||||||
*
|
*
|
||||||
* @author Mark Hilbush - Initial contribution
|
* @author Mark Hilbush - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class BigAssFanDevice {
|
public class BigAssFanDevice {
|
||||||
/**
|
/**
|
||||||
* Name of device (e.g. Master Bedroom Fan)
|
* Name of device (e.g. Master Bedroom Fan)
|
||||||
*/
|
*/
|
||||||
private String label;
|
private String label = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IP address of the device extracted from UDP packet
|
* IP address of the device extracted from UDP packet
|
||||||
*/
|
*/
|
||||||
private String ipAddress;
|
private String ipAddress = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MAC address of the device extracted from discovery message
|
* MAC address of the device extracted from discovery message
|
||||||
*/
|
*/
|
||||||
private String macAddress;
|
private String macAddress = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of device extracted from discovery message (e.g. FAN or SWITCH)
|
* Type of device extracted from discovery message (e.g. FAN or SWITCH)
|
||||||
*/
|
*/
|
||||||
private String type;
|
private String type = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of device extracted from discovery message (e.g. HSERIES)
|
* Model of device extracted from discovery message (e.g. HSERIES)
|
||||||
*/
|
*/
|
||||||
private String model;
|
private String model = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The raw discovery message
|
* The raw discovery message
|
||||||
*/
|
*/
|
||||||
private String discoveryMessage;
|
private String discoveryMessage = "";
|
||||||
|
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
|
|
|
@ -27,6 +27,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
import org.openhab.core.config.discovery.DiscoveryService;
|
||||||
|
@ -44,6 +46,7 @@ import org.slf4j.LoggerFactory;
|
||||||
*
|
*
|
||||||
* @author Mark Hilbush - Initial contribution
|
* @author Mark Hilbush - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
@Component(service = DiscoveryService.class, configurationPid = "discovery.bigassfan")
|
@Component(service = DiscoveryService.class, configurationPid = "discovery.bigassfan")
|
||||||
public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
private final Logger logger = LoggerFactory.getLogger(BigAssFanDiscoveryService.class);
|
private final Logger logger = LoggerFactory.getLogger(BigAssFanDiscoveryService.class);
|
||||||
|
@ -53,12 +56,9 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
|
|
||||||
// Our own thread pool for the long-running listener job
|
// Our own thread pool for the long-running listener job
|
||||||
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
|
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
|
||||||
private ScheduledFuture<?> listenerJob;
|
private @Nullable ScheduledFuture<?> listenerJob;
|
||||||
|
private @Nullable DiscoveryListener discoveryListener;
|
||||||
DiscoveryListener discoveryListener;
|
|
||||||
|
|
||||||
private boolean terminate;
|
private boolean terminate;
|
||||||
|
|
||||||
private final Pattern announcementPattern = Pattern.compile("[(](.*);DEVICE;ID;(.*);(.*)[)]");
|
private final Pattern announcementPattern = Pattern.compile("[(](.*);DEVICE;ID;(.*);(.*)[)]");
|
||||||
|
|
||||||
private Runnable listenerRunnable = () -> {
|
private Runnable listenerRunnable = () -> {
|
||||||
|
@ -70,9 +70,9 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Frequency (in seconds) with which we poll for new devices
|
// Frequency (in seconds) with which we poll for new devices
|
||||||
private final long POLL_FREQ = 300L;
|
private static final long POLL_FREQ = 300L;
|
||||||
private final long POLL_DELAY = 12L;
|
private static final long POLL_DELAY = 12L;
|
||||||
private ScheduledFuture<?> pollJob;
|
private @Nullable ScheduledFuture<?> pollJob;
|
||||||
|
|
||||||
public BigAssFanDiscoveryService() {
|
public BigAssFanDiscoveryService() {
|
||||||
super(SUPPORTED_THING_TYPES_UIDS, 0, BACKGROUND_DISCOVERY_ENABLED);
|
super(SUPPORTED_THING_TYPES_UIDS, 0, BACKGROUND_DISCOVERY_ENABLED);
|
||||||
|
@ -84,7 +84,7 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate(Map<String, Object> configProperties) {
|
protected void activate(@Nullable Map<String, Object> configProperties) {
|
||||||
super.activate(configProperties);
|
super.activate(configProperties);
|
||||||
logger.trace("BigAssFan discovery service ACTIVATED");
|
logger.trace("BigAssFan discovery service ACTIVATED");
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Modified
|
@Modified
|
||||||
protected void modified(Map<String, Object> configProperties) {
|
protected void modified(@Nullable Map<String, Object> configProperties) {
|
||||||
super.modified(configProperties);
|
super.modified(configProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,21 +115,22 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
cancelListenerJob();
|
cancelListenerJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startListenerJob() {
|
private synchronized void startListenerJob() {
|
||||||
if (listenerJob == null) {
|
if (this.listenerJob == null) {
|
||||||
terminate = false;
|
|
||||||
logger.debug("Starting discovery listener job in {} seconds", BACKGROUND_DISCOVERY_DELAY);
|
logger.debug("Starting discovery listener job in {} seconds", BACKGROUND_DISCOVERY_DELAY);
|
||||||
listenerJob = scheduledExecutorService.schedule(listenerRunnable, BACKGROUND_DISCOVERY_DELAY,
|
terminate = false;
|
||||||
|
this.listenerJob = scheduledExecutorService.schedule(listenerRunnable, BACKGROUND_DISCOVERY_DELAY,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelListenerJob() {
|
private void cancelListenerJob() {
|
||||||
if (listenerJob != null) {
|
ScheduledFuture<?> localListenerJob = this.listenerJob;
|
||||||
|
if (localListenerJob != null) {
|
||||||
logger.debug("Canceling discovery listener job");
|
logger.debug("Canceling discovery listener job");
|
||||||
listenerJob.cancel(true);
|
localListenerJob.cancel(true);
|
||||||
terminate = true;
|
terminate = true;
|
||||||
listenerJob = null;
|
this.listenerJob = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,9 +144,11 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
|
|
||||||
private synchronized void listen() {
|
private synchronized void listen() {
|
||||||
logger.info("BigAssFan discovery service is running");
|
logger.info("BigAssFan discovery service is running");
|
||||||
|
DiscoveryListener localDiscoveryListener;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
discoveryListener = new DiscoveryListener();
|
localDiscoveryListener = new DiscoveryListener();
|
||||||
|
discoveryListener = localDiscoveryListener;
|
||||||
} catch (SocketException se) {
|
} catch (SocketException se) {
|
||||||
logger.warn("Got Socket exception creating multicast socket: {}", se.getMessage(), se);
|
logger.warn("Got Socket exception creating multicast socket: {}", se.getMessage(), se);
|
||||||
return;
|
return;
|
||||||
|
@ -158,7 +161,7 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
while (!terminate) {
|
while (!terminate) {
|
||||||
try {
|
try {
|
||||||
// Wait for a discovery message
|
// Wait for a discovery message
|
||||||
processMessage(discoveryListener.waitForMessage());
|
processMessage(localDiscoveryListener.waitForMessage());
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
// Read on socket timed out; check for termination
|
// Read on socket timed out; check for termination
|
||||||
continue;
|
continue;
|
||||||
|
@ -167,14 +170,11 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
discoveryListener.shutdown();
|
localDiscoveryListener.shutdown();
|
||||||
logger.debug("DiscoveryListener job is exiting");
|
logger.debug("DiscoveryListener job is exiting");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processMessage(BigAssFanDevice device) {
|
private void processMessage(BigAssFanDevice device) {
|
||||||
if (device == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Matcher matcher = announcementPattern.matcher(device.getDiscoveryMessage());
|
Matcher matcher = announcementPattern.matcher(device.getDiscoveryMessage());
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
logger.debug("Match: grp1={}, grp2={}, grp(3)={}", matcher.group(1), matcher.group(2), matcher.group(3));
|
logger.debug("Match: grp1={}, grp2={}, grp(3)={}", matcher.group(1), matcher.group(2), matcher.group(3));
|
||||||
|
@ -242,23 +242,30 @@ public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
|
||||||
.withRepresentationProperty(THING_PROPERTY_MAC).withLabel(device.getLabel()).build());
|
.withRepresentationProperty(THING_PROPERTY_MAC).withLabel(device.getLabel()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void schedulePollJob() {
|
private synchronized void schedulePollJob() {
|
||||||
logger.debug("Scheduling discovery poll job to run every {} seconds starting in {} sec", POLL_FREQ, POLL_DELAY);
|
|
||||||
cancelPollJob();
|
cancelPollJob();
|
||||||
pollJob = scheduler.scheduleWithFixedDelay(() -> {
|
if (this.pollJob == null) {
|
||||||
try {
|
logger.debug("Scheduling discovery poll job to run every {} seconds starting in {} sec", POLL_FREQ,
|
||||||
discoveryListener.pollForDevices();
|
POLL_DELAY);
|
||||||
} catch (RuntimeException e) {
|
pollJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||||
logger.warn("Poll job got unexpected exception: {}", e.getMessage(), e);
|
try {
|
||||||
}
|
DiscoveryListener localListener = discoveryListener;
|
||||||
}, POLL_DELAY, POLL_FREQ, TimeUnit.SECONDS);
|
if (localListener != null) {
|
||||||
|
localListener.pollForDevices();
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.warn("Poll job got unexpected exception: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}, POLL_DELAY, POLL_FREQ, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelPollJob() {
|
private void cancelPollJob() {
|
||||||
if (pollJob != null) {
|
ScheduledFuture<?> localPollJob = pollJob;
|
||||||
|
if (localPollJob != null) {
|
||||||
logger.debug("Canceling poll job");
|
logger.debug("Canceling poll job");
|
||||||
pollJob.cancel(true);
|
localPollJob.cancel(true);
|
||||||
pollJob = null;
|
this.pollJob = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ import java.net.SocketTimeoutException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -31,19 +33,23 @@ import org.slf4j.LoggerFactory;
|
||||||
*
|
*
|
||||||
* @author Mark Hilbush - Initial contribution
|
* @author Mark Hilbush - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class DiscoveryListener {
|
public class DiscoveryListener {
|
||||||
private final Logger logger = LoggerFactory.getLogger(DiscoveryListener.class);
|
private final Logger logger = LoggerFactory.getLogger(DiscoveryListener.class);
|
||||||
|
|
||||||
private final String BCAST_ADDRESS = "255.255.255.255";
|
private static final String BCAST_ADDRESS = "255.255.255.255";
|
||||||
private final int SOCKET_RECEIVE_TIMEOUT = 500;
|
private static final int SOCKET_RECEIVE_TIMEOUT = 500;
|
||||||
|
private static final String POLL_MESSAGE = "<ALL;DEVICE;ID;GET>";
|
||||||
private final String POLL_MESSAGE = "<ALL;DEVICE;ID;GET>";
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
DatagramSocket dSocket;
|
DatagramSocket dSocket;
|
||||||
|
@Nullable
|
||||||
DatagramPacket rcvPacket;
|
DatagramPacket rcvPacket;
|
||||||
byte[] rcvBuffer;
|
byte[] rcvBuffer = new byte[0];
|
||||||
|
@Nullable
|
||||||
InetAddress bcastAddress;
|
InetAddress bcastAddress;
|
||||||
byte[] bcastBuffer;
|
byte[] bcastBuffer = new byte[0];
|
||||||
|
@Nullable
|
||||||
DatagramPacket bcastPacket;
|
DatagramPacket bcastPacket;
|
||||||
|
|
||||||
BigAssFanDevice device;
|
BigAssFanDevice device;
|
||||||
|
@ -54,52 +60,66 @@ public class DiscoveryListener {
|
||||||
device = new BigAssFanDevice();
|
device = new BigAssFanDevice();
|
||||||
try {
|
try {
|
||||||
// Create a socket on the UDP port and get send & receive buffers
|
// Create a socket on the UDP port and get send & receive buffers
|
||||||
dSocket = new DatagramSocket(BAF_PORT);
|
DatagramSocket localDatagramSocket = new DatagramSocket(BAF_PORT);
|
||||||
dSocket.setSoTimeout(SOCKET_RECEIVE_TIMEOUT);
|
localDatagramSocket.setSoTimeout(SOCKET_RECEIVE_TIMEOUT);
|
||||||
dSocket.setBroadcast(true);
|
localDatagramSocket.setBroadcast(true);
|
||||||
|
dSocket = localDatagramSocket;
|
||||||
rcvBuffer = new byte[256];
|
rcvBuffer = new byte[256];
|
||||||
rcvPacket = new DatagramPacket(rcvBuffer, rcvBuffer.length);
|
rcvPacket = new DatagramPacket(rcvBuffer, rcvBuffer.length);
|
||||||
bcastAddress = InetAddress.getByName(BCAST_ADDRESS);
|
bcastAddress = InetAddress.getByName(BCAST_ADDRESS);
|
||||||
bcastBuffer = POLL_MESSAGE.getBytes(StandardCharsets.US_ASCII);
|
bcastBuffer = POLL_MESSAGE.getBytes(StandardCharsets.US_ASCII);
|
||||||
bcastPacket = new DatagramPacket(bcastBuffer, bcastBuffer.length, bcastAddress, BAF_PORT);
|
bcastPacket = new DatagramPacket(bcastBuffer, bcastBuffer.length, bcastAddress, BAF_PORT);
|
||||||
} catch (UnknownHostException uhe) {
|
} catch (UnknownHostException | SocketException | SecurityException e) {
|
||||||
logger.warn("UnknownHostException sending poll request for fans: {}", uhe.getMessage(), uhe);
|
logger.warn("Unexpected exception sending poll request for fans: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigAssFanDevice waitForMessage() throws IOException, SocketTimeoutException {
|
public BigAssFanDevice waitForMessage() throws IOException, SocketTimeoutException {
|
||||||
// Wait to receive a packet
|
// Wait to receive a packet
|
||||||
rcvPacket.setLength(rcvBuffer.length);
|
DatagramPacket localPacket = rcvPacket;
|
||||||
dSocket.receive(rcvPacket);
|
DatagramSocket localDatagramSocket = dSocket;
|
||||||
|
|
||||||
// Process the received packet
|
if (localPacket != null) {
|
||||||
device.reset();
|
localPacket.setLength(rcvBuffer.length);
|
||||||
device.setIpAddress(rcvPacket.getAddress().getHostAddress());
|
}
|
||||||
String message = (new String(rcvBuffer, 0, rcvPacket.getLength()));
|
|
||||||
device.setDiscoveryMessage(message);
|
if (localDatagramSocket != null && localPacket != null) {
|
||||||
logger.debug("RECEIVED packet of length {} from {}: {}", message.length(), device.getIpAddress(), message);
|
localDatagramSocket.receive(localPacket);
|
||||||
|
|
||||||
|
// Process the received packet
|
||||||
|
device.reset();
|
||||||
|
|
||||||
|
String address = localPacket.getAddress().getHostAddress();
|
||||||
|
device.setIpAddress(address != null ? address : "");
|
||||||
|
|
||||||
|
String message = (new String(rcvBuffer, 0, localPacket.getLength()));
|
||||||
|
device.setDiscoveryMessage(message);
|
||||||
|
logger.debug("RECEIVED packet of length {} from {}: {}", message.length(), device.getIpAddress(), message);
|
||||||
|
}
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pollForDevices() {
|
public void pollForDevices() {
|
||||||
if (dSocket == null) {
|
DatagramSocket localDatagramSocket = dSocket;
|
||||||
|
if (localDatagramSocket == null) {
|
||||||
logger.debug("Socket is null in discoveryListener.pollForDevices()");
|
logger.debug("Socket is null in discoveryListener.pollForDevices()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Sending poll request for fans: {}", POLL_MESSAGE);
|
logger.debug("Sending poll request for fans: {}", POLL_MESSAGE);
|
||||||
try {
|
try {
|
||||||
dSocket.send(bcastPacket);
|
localDatagramSocket.send(bcastPacket);
|
||||||
} catch (IOException ioe) {
|
} catch (IllegalArgumentException | SecurityException | IOException e) {
|
||||||
logger.warn("IOException sending poll request for fans: {}", ioe.getMessage(), ioe);
|
logger.warn("Unexpected exception while sending poll request for fans: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
logger.debug("DiscoveryListener closing socket");
|
logger.debug("DiscoveryListener closing socket");
|
||||||
if (dSocket != null) {
|
DatagramSocket localDatagramSocket = dSocket;
|
||||||
dSocket.close();
|
if (localDatagramSocket != null) {
|
||||||
|
localDatagramSocket.close();
|
||||||
dSocket = null;
|
dSocket = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
|
import java.nio.channels.IllegalBlockingModeException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
@ -40,6 +41,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.bigassfan.internal.BigAssFanConfig;
|
import org.openhab.binding.bigassfan.internal.BigAssFanConfig;
|
||||||
import org.openhab.binding.bigassfan.internal.utils.BigAssFanConverter;
|
import org.openhab.binding.bigassfan.internal.utils.BigAssFanConverter;
|
||||||
import org.openhab.core.common.ThreadPoolManager;
|
import org.openhab.core.common.ThreadPoolManager;
|
||||||
|
@ -65,6 +68,7 @@ import org.slf4j.LoggerFactory;
|
||||||
*
|
*
|
||||||
* @author Mark Hilbush - Initial contribution
|
* @author Mark Hilbush - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class BigAssFanHandler extends BaseThingHandler {
|
public class BigAssFanHandler extends BaseThingHandler {
|
||||||
private final Logger logger = LoggerFactory.getLogger(BigAssFanHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(BigAssFanHandler.class);
|
||||||
|
|
||||||
|
@ -75,16 +79,15 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
private static final StringType COOLING = new StringType("COOLING");
|
private static final StringType COOLING = new StringType("COOLING");
|
||||||
private static final StringType HEATING = new StringType("HEATING");
|
private static final StringType HEATING = new StringType("HEATING");
|
||||||
|
|
||||||
private BigAssFanConfig config;
|
private String label = "";
|
||||||
private String label = null;
|
private String ipAddress = "";
|
||||||
private String ipAddress = null;
|
private String macAddress = "";
|
||||||
private String macAddress = null;
|
|
||||||
|
|
||||||
private FanListener fanListener;
|
private final FanListener fanListener;
|
||||||
|
|
||||||
protected Map<String, State> fanStateMap = Collections.synchronizedMap(new HashMap<>());
|
protected final Map<String, State> fanStateMap = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
public BigAssFanHandler(Thing thing, String ipv4Address) {
|
public BigAssFanHandler(Thing thing, @Nullable String ipv4Address) {
|
||||||
super(thing);
|
super(thing);
|
||||||
this.thing = thing;
|
this.thing = thing;
|
||||||
|
|
||||||
|
@ -96,18 +99,19 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
logger.debug("BigAssFanHandler for {} is initializing", thing.getUID());
|
logger.debug("BigAssFanHandler for {} is initializing", thing.getUID());
|
||||||
|
|
||||||
config = getConfig().as(BigAssFanConfig.class);
|
BigAssFanConfig configuration = getConfig().as(BigAssFanConfig.class);
|
||||||
logger.debug("BigAssFanHandler config for {} is {}", thing.getUID(), config);
|
logger.debug("BigAssFanHandler config for {} is {}", thing.getUID(), configuration);
|
||||||
|
|
||||||
if (!config.isValid()) {
|
if (!configuration.isValid()) {
|
||||||
logger.debug("BigAssFanHandler config of {} is invalid. Check configuration", thing.getUID());
|
logger.debug("BigAssFanHandler config of {} is invalid. Check configuration", thing.getUID());
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"Invalid BigAssFan config. Check configuration.");
|
"Invalid BigAssFan config. Check configuration.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
label = config.getLabel();
|
|
||||||
ipAddress = config.getIpAddress();
|
label = configuration.getLabel();
|
||||||
macAddress = config.getMacAddress();
|
ipAddress = configuration.getIpAddress();
|
||||||
|
macAddress = configuration.getMacAddress();
|
||||||
|
|
||||||
fanListener.startFanListener();
|
fanListener.startFanListener();
|
||||||
}
|
}
|
||||||
|
@ -312,8 +316,9 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
private void adjustMaxSpeed(PercentType command, String channelId, String commandFragment) {
|
private void adjustMaxSpeed(PercentType command, String channelId, String commandFragment) {
|
||||||
int newMin = command.intValue();
|
int newMin = command.intValue();
|
||||||
int currentMax = PercentType.ZERO.intValue();
|
int currentMax = PercentType.ZERO.intValue();
|
||||||
if (fanStateMap.get(channelId) != null) {
|
State fanState = fanStateMap.get(channelId);
|
||||||
currentMax = ((PercentType) fanStateMap.get(channelId)).intValue();
|
if (fanState != null) {
|
||||||
|
currentMax = ((PercentType) fanState).intValue();
|
||||||
}
|
}
|
||||||
if (newMin > currentMax) {
|
if (newMin > currentMax) {
|
||||||
updateState(CHANNEL_FAN_SPEED_MAX, command);
|
updateState(CHANNEL_FAN_SPEED_MAX, command);
|
||||||
|
@ -324,8 +329,9 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
private void adjustMinSpeed(PercentType command, String channelId, String commandFragment) {
|
private void adjustMinSpeed(PercentType command, String channelId, String commandFragment) {
|
||||||
int newMax = command.intValue();
|
int newMax = command.intValue();
|
||||||
int currentMin = PercentType.HUNDRED.intValue();
|
int currentMin = PercentType.HUNDRED.intValue();
|
||||||
if (fanStateMap.get(channelId) != null) {
|
State fanSate = fanStateMap.get(channelId);
|
||||||
currentMin = ((PercentType) fanStateMap.get(channelId)).intValue();
|
if (fanSate != null) {
|
||||||
|
currentMin = ((PercentType) fanSate).intValue();
|
||||||
}
|
}
|
||||||
if (newMax < currentMin) {
|
if (newMax < currentMin) {
|
||||||
updateState(channelId, command);
|
updateState(channelId, command);
|
||||||
|
@ -449,8 +455,9 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
private void adjustMaxLevel(PercentType command) {
|
private void adjustMaxLevel(PercentType command) {
|
||||||
int newMin = command.intValue();
|
int newMin = command.intValue();
|
||||||
int currentMax = PercentType.ZERO.intValue();
|
int currentMax = PercentType.ZERO.intValue();
|
||||||
if (fanStateMap.get(CHANNEL_LIGHT_LEVEL_MAX) != null) {
|
State fanState = fanStateMap.get(CHANNEL_LIGHT_LEVEL_MAX);
|
||||||
currentMax = ((PercentType) fanStateMap.get(CHANNEL_LIGHT_LEVEL_MAX)).intValue();
|
if (fanState != null) {
|
||||||
|
currentMax = ((PercentType) fanState).intValue();
|
||||||
}
|
}
|
||||||
if (newMin > currentMax) {
|
if (newMin > currentMax) {
|
||||||
updateState(CHANNEL_LIGHT_LEVEL_MAX, command);
|
updateState(CHANNEL_LIGHT_LEVEL_MAX, command);
|
||||||
|
@ -461,8 +468,9 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
private void adjustMinLevel(PercentType command) {
|
private void adjustMinLevel(PercentType command) {
|
||||||
int newMax = command.intValue();
|
int newMax = command.intValue();
|
||||||
int currentMin = PercentType.HUNDRED.intValue();
|
int currentMin = PercentType.HUNDRED.intValue();
|
||||||
if (fanStateMap.get(CHANNEL_LIGHT_LEVEL_MIN) != null) {
|
State fanState = fanStateMap.get(CHANNEL_LIGHT_LEVEL_MIN);
|
||||||
currentMin = ((PercentType) fanStateMap.get(CHANNEL_LIGHT_LEVEL_MIN)).intValue();
|
if (fanState != null) {
|
||||||
|
currentMin = ((PercentType) fanState).intValue();
|
||||||
}
|
}
|
||||||
if (newMax < currentMin) {
|
if (newMax < currentMin) {
|
||||||
updateState(CHANNEL_LIGHT_LEVEL_MIN, command);
|
updateState(CHANNEL_LIGHT_LEVEL_MIN, command);
|
||||||
|
@ -483,11 +491,6 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
* Send a command to the fan
|
* Send a command to the fan
|
||||||
*/
|
*/
|
||||||
private void sendCommand(String mac, String commandFragment) {
|
private void sendCommand(String mac, String commandFragment) {
|
||||||
if (fanListener == null) {
|
|
||||||
logger.error("Unable to send message to {} because fanListener object is null!", thing.getUID());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("<").append(mac).append(commandFragment).append(">");
|
sb.append("<").append(mac).append(commandFragment).append(">");
|
||||||
String message = sb.toString();
|
String message = sb.toString();
|
||||||
|
@ -519,7 +522,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markOfflineWithMessage(ThingStatusDetail statusDetail, String statusMessage) {
|
private void markOfflineWithMessage(ThingStatusDetail statusDetail, @Nullable String statusMessage) {
|
||||||
// If it's offline with no detail or if it's not offline, mark it offline with detailed status
|
// If it's offline with no detail or if it's not offline, mark it offline with detailed status
|
||||||
if ((isOffline() && getDetail() == ThingStatusDetail.NONE) || !isOffline()) {
|
if ((isOffline() && getDetail() == ThingStatusDetail.NONE) || !isOffline()) {
|
||||||
logger.debug("Changing status of {} from {}({}) to OFFLINE({})", thing.getUID(), getStatus(), getDetail(),
|
logger.debug("Changing status of {} from {}({}) to OFFLINE({})", thing.getUID(), getStatus(), getDetail(),
|
||||||
|
@ -556,9 +559,9 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
// Our own thread pool for the long-running listener job
|
// Our own thread pool for the long-running listener job
|
||||||
private ScheduledExecutorService scheduledExecutorService = ThreadPoolManager
|
private ScheduledExecutorService scheduledExecutorService = ThreadPoolManager
|
||||||
.getScheduledPool("bigassfanHandler" + "-" + thing.getUID());
|
.getScheduledPool("bigassfanHandler" + "-" + thing.getUID());
|
||||||
private ScheduledFuture<?> listenerJob;
|
private @Nullable ScheduledFuture<?> listenerJob;
|
||||||
|
|
||||||
private final long FAN_LISTENER_DELAY = 2L;
|
private static final long FAN_LISTENER_DELAY = 2L;
|
||||||
private boolean terminate;
|
private boolean terminate;
|
||||||
|
|
||||||
private final Pattern messagePattern = Pattern.compile("[(](.*)");
|
private final Pattern messagePattern = Pattern.compile("[(](.*)");
|
||||||
|
@ -573,7 +576,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public FanListener(String ipv4Address) {
|
public FanListener(@Nullable String ipv4Address) {
|
||||||
conn = new ConnectionManager(ipv4Address);
|
conn = new ConnectionManager(ipv4Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,12 +593,14 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopFanListener() {
|
public void stopFanListener() {
|
||||||
if (listenerJob != null) {
|
ScheduledFuture<?> localListenerJob = listenerJob;
|
||||||
|
if (localListenerJob != null) {
|
||||||
logger.debug("Stopping listener for {} at {}", thing.getUID(), ipAddress);
|
logger.debug("Stopping listener for {} at {}", thing.getUID(), ipAddress);
|
||||||
terminate = true;
|
terminate = true;
|
||||||
listenerJob.cancel(true);
|
localListenerJob.cancel(true);
|
||||||
listenerJob = null;
|
this.listenerJob = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.cancelConnectionMonitorJob();
|
conn.cancelConnectionMonitorJob();
|
||||||
conn.disconnect();
|
conn.disconnect();
|
||||||
}
|
}
|
||||||
|
@ -636,7 +641,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
logger.debug("Fan listener thread is exiting for {} at {}", thing.getUID(), ipAddress);
|
logger.debug("Fan listener thread is exiting for {} at {}", thing.getUID(), ipAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String waitForMessage() throws IOException {
|
private @Nullable String waitForMessage() throws IOException {
|
||||||
if (!conn.isConnected()) {
|
if (!conn.isConnected()) {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("FanListener for {} can't receive message. No connection to fan", thing.getUID());
|
logger.trace("FanListener for {} can't receive message. No connection to fan", thing.getUID());
|
||||||
|
@ -650,7 +655,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
return readMessage();
|
return readMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readMessage() {
|
private @Nullable String readMessage() {
|
||||||
logger.trace("Waiting for message from {} at {}", thing.getUID(), ipAddress);
|
logger.trace("Waiting for message from {} at {}", thing.getUID(), ipAddress);
|
||||||
String message = conn.read();
|
String message = conn.read();
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
|
@ -660,7 +665,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processMessage(String incomingMessage) {
|
private void processMessage(@Nullable String incomingMessage) {
|
||||||
if (incomingMessage == null || incomingMessage.isEmpty()) {
|
if (incomingMessage == null || incomingMessage.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -739,10 +744,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Didn't match MAC address, check match for label
|
// Didn't match MAC address, check match for label
|
||||||
if (label.equalsIgnoreCase(idFromDevice)) {
|
return label.equalsIgnoreCase(idFromDevice);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFanPower(String[] messageParts) {
|
private void updateFanPower(String[] messageParts) {
|
||||||
|
@ -1003,27 +1005,28 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
|
|
||||||
private boolean deviceIsConnected;
|
private boolean deviceIsConnected;
|
||||||
|
|
||||||
private InetAddress ifAddress;
|
private @Nullable InetAddress ifAddress;
|
||||||
private Socket fanSocket;
|
private @Nullable Socket fanSocket;
|
||||||
private Scanner fanScanner;
|
private @Nullable Scanner fanScanner;
|
||||||
private DataOutputStream fanWriter;
|
private @Nullable DataOutputStream fanWriter;
|
||||||
private final int SOCKET_CONNECT_TIMEOUT = 1500;
|
private static final int SOCKET_CONNECT_TIMEOUT = 1500;
|
||||||
|
|
||||||
ScheduledFuture<?> connectionMonitorJob;
|
private @Nullable ScheduledFuture<?> connectionMonitorJob;
|
||||||
private final long CONNECTION_MONITOR_FREQ = 120L;
|
private static final long CONNECTION_MONITOR_FREQ = 120L;
|
||||||
private final long CONNECTION_MONITOR_DELAY = 30L;
|
private static final long CONNECTION_MONITOR_DELAY = 30L;
|
||||||
|
|
||||||
Runnable connectionMonitorRunnable = () -> {
|
Runnable connectionMonitorRunnable = () -> {
|
||||||
logger.trace("Performing connection check for {} at IP {}", thing.getUID(), ipAddress);
|
logger.trace("Performing connection check for {} at IP {}", thing.getUID(), ipAddress);
|
||||||
checkConnection();
|
checkConnection();
|
||||||
};
|
};
|
||||||
|
|
||||||
public ConnectionManager(String ipv4Address) {
|
public ConnectionManager(@Nullable String ipv4Address) {
|
||||||
deviceIsConnected = false;
|
deviceIsConnected = false;
|
||||||
try {
|
try {
|
||||||
ifAddress = InetAddress.getByName(ipv4Address);
|
ifAddress = InetAddress.getByName(ipv4Address);
|
||||||
logger.debug("Handler for {} using address {} on network interface {}", thing.getUID(),
|
|
||||||
ifAddress.getHostAddress(), NetworkInterface.getByInetAddress(ifAddress).getName());
|
logger.debug("Handler for {} using address {} on network interface {}", thing.getUID(), ipv4Address,
|
||||||
|
NetworkInterface.getByInetAddress(ifAddress).getName());
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
logger.warn("Handler for {} got UnknownHostException getting local IPv4 net interface: {}",
|
logger.warn("Handler for {} got UnknownHostException getting local IPv4 net interface: {}",
|
||||||
thing.getUID(), e.getMessage(), e);
|
thing.getUID(), e.getMessage(), e);
|
||||||
|
@ -1045,13 +1048,15 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
logger.trace("Connecting to {} at {}", thing.getUID(), ipAddress);
|
logger.trace("Connecting to {} at {}", thing.getUID(), ipAddress);
|
||||||
|
|
||||||
|
Socket localFanSocket = new Socket();
|
||||||
|
fanSocket = localFanSocket;
|
||||||
// Open socket
|
// Open socket
|
||||||
try {
|
try {
|
||||||
fanSocket = new Socket();
|
localFanSocket.bind(new InetSocketAddress(ifAddress, 0));
|
||||||
fanSocket.bind(new InetSocketAddress(ifAddress, 0));
|
localFanSocket.connect(new InetSocketAddress(ipAddress, BAF_PORT), SOCKET_CONNECT_TIMEOUT);
|
||||||
fanSocket.connect(new InetSocketAddress(ipAddress, BAF_PORT), SOCKET_CONNECT_TIMEOUT);
|
} catch (SecurityException | IllegalArgumentException | IOException e) {
|
||||||
} catch (IOException e) {
|
logger.debug("Unexpected exception connecting to {} at {}: {}", thing.getUID(), ipAddress,
|
||||||
logger.debug("IOException connecting to {} at {}: {}", thing.getUID(), ipAddress, e.getMessage());
|
e.getMessage(), e);
|
||||||
markOfflineWithMessage(ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
|
markOfflineWithMessage(ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
|
||||||
disconnect();
|
disconnect();
|
||||||
return;
|
return;
|
||||||
|
@ -1059,12 +1064,12 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
|
|
||||||
// Create streams
|
// Create streams
|
||||||
try {
|
try {
|
||||||
fanWriter = new DataOutputStream(fanSocket.getOutputStream());
|
fanWriter = new DataOutputStream(localFanSocket.getOutputStream());
|
||||||
fanScanner = new Scanner(fanSocket.getInputStream());
|
Scanner localFanScanner = new Scanner(localFanSocket.getInputStream());
|
||||||
fanScanner.useDelimiter("[)]");
|
localFanScanner.useDelimiter("[)]");
|
||||||
} catch (IOException e) {
|
fanScanner = localFanScanner;
|
||||||
logger.warn("IOException getting streams for {} at {}: {}", thing.getUID(), ipAddress, e.getMessage(),
|
} catch (IllegalBlockingModeException | IOException e) {
|
||||||
e);
|
logger.warn("Exception getting streams for {} at {}: {}", thing.getUID(), ipAddress, e.getMessage(), e);
|
||||||
markOfflineWithMessage(ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
|
markOfflineWithMessage(ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
|
||||||
disconnect();
|
disconnect();
|
||||||
return;
|
return;
|
||||||
|
@ -1081,17 +1086,22 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
logger.debug("Disconnecting from {} at {}", thing.getUID(), ipAddress);
|
logger.debug("Disconnecting from {} at {}", thing.getUID(), ipAddress);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (fanWriter != null) {
|
DataOutputStream localFanWriter = fanWriter;
|
||||||
fanWriter.close();
|
if (localFanWriter != null) {
|
||||||
|
localFanWriter.close();
|
||||||
|
fanWriter = null;
|
||||||
}
|
}
|
||||||
if (fanScanner != null) {
|
Scanner localFanScanner = fanScanner;
|
||||||
fanScanner.close();
|
if (localFanScanner != null) {
|
||||||
|
localFanScanner.close();
|
||||||
}
|
}
|
||||||
if (fanSocket != null) {
|
Socket localFanSocket = fanSocket;
|
||||||
fanSocket.close();
|
if (localFanSocket != null) {
|
||||||
|
localFanSocket.close();
|
||||||
|
fanSocket = null;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IllegalStateException | IOException e) {
|
||||||
logger.warn("IOException closing connection to {} at {}: {}", thing.getUID(), ipAddress, e.getMessage(),
|
logger.warn("Exception closing connection to {} at {}: {}", thing.getUID(), ipAddress, e.getMessage(),
|
||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
deviceIsConnected = false;
|
deviceIsConnected = false;
|
||||||
|
@ -1101,15 +1111,18 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
markOffline();
|
markOffline();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String read() {
|
public @Nullable String read() {
|
||||||
if (fanScanner == null) {
|
if (fanScanner == null) {
|
||||||
logger.warn("Scanner for {} is null when trying to scan from {}!", thing.getUID(), ipAddress);
|
logger.warn("Scanner for {} is null when trying to scan from {}!", thing.getUID(), ipAddress);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String nextToken;
|
String nextToken = null;
|
||||||
try {
|
try {
|
||||||
nextToken = fanScanner.next();
|
Scanner localFanScanner = fanScanner;
|
||||||
|
if (localFanScanner != null) {
|
||||||
|
nextToken = localFanScanner.next();
|
||||||
|
}
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
logger.debug("Scanner for {} threw NoSuchElementException; stream possibly closed", thing.getUID());
|
logger.debug("Scanner for {} threw NoSuchElementException; stream possibly closed", thing.getUID());
|
||||||
// Force a reconnect to the device
|
// Force a reconnect to the device
|
||||||
|
@ -1126,11 +1139,13 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(byte[] buffer) throws IOException {
|
public void write(byte[] buffer) throws IOException {
|
||||||
if (fanWriter == null) {
|
DataOutputStream localFanWriter = fanWriter;
|
||||||
|
if (localFanWriter == null) {
|
||||||
logger.warn("fanWriter for {} is null when trying to write to {}!!!", thing.getUID(), ipAddress);
|
logger.warn("fanWriter for {} is null when trying to write to {}!!!", thing.getUID(), ipAddress);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
localFanWriter.write(buffer, 0, buffer.length);
|
||||||
}
|
}
|
||||||
fanWriter.write(buffer, 0, buffer.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isConnected() {
|
private boolean isConnected() {
|
||||||
|
@ -1140,7 +1155,7 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
/*
|
/*
|
||||||
* Periodically validate the command connection to the device by executing a getversion command.
|
* Periodically validate the command connection to the device by executing a getversion command.
|
||||||
*/
|
*/
|
||||||
private void scheduleConnectionMonitorJob() {
|
private synchronized void scheduleConnectionMonitorJob() {
|
||||||
if (connectionMonitorJob == null) {
|
if (connectionMonitorJob == null) {
|
||||||
logger.debug("Starting connection monitor job in {} seconds for {} at {}", CONNECTION_MONITOR_DELAY,
|
logger.debug("Starting connection monitor job in {} seconds for {} at {}", CONNECTION_MONITOR_DELAY,
|
||||||
thing.getUID(), ipAddress);
|
thing.getUID(), ipAddress);
|
||||||
|
@ -1150,9 +1165,10 @@ public class BigAssFanHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelConnectionMonitorJob() {
|
private void cancelConnectionMonitorJob() {
|
||||||
if (connectionMonitorJob != null) {
|
ScheduledFuture<?> localConnectionMonitorJob = connectionMonitorJob;
|
||||||
|
if (localConnectionMonitorJob != null) {
|
||||||
logger.debug("Canceling connection monitor job for {} at {}", thing.getUID(), ipAddress);
|
logger.debug("Canceling connection monitor job for {} at {}", thing.getUID(), ipAddress);
|
||||||
connectionMonitorJob.cancel(true);
|
localConnectionMonitorJob.cancel(true);
|
||||||
connectionMonitorJob = null;
|
connectionMonitorJob = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.bigassfan.internal.utils;
|
package org.openhab.binding.bigassfan.internal.utils;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.library.types.PercentType;
|
import org.openhab.core.library.types.PercentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +22,7 @@ import org.openhab.core.library.types.PercentType;
|
||||||
*
|
*
|
||||||
* @author Mark Hilbush - Initial contribution
|
* @author Mark Hilbush - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class BigAssFanConverter {
|
public class BigAssFanConverter {
|
||||||
/*
|
/*
|
||||||
* Conversion factor for fan range (0-7) to dimmer range (0-100).
|
* Conversion factor for fan range (0-7) to dimmer range (0-100).
|
||||||
|
|
Loading…
Reference in New Issue