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