[airvisualnode] Add null annotations (#13895)

* Add null annotation

Signed-off-by: Leo Siepel <leosiepel@gmail.com>
This commit is contained in:
lsiepel 2022-12-26 17:00:53 +01:00 committed by GitHub
parent 88c0b720c6
commit 1c5b794145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 114 additions and 90 deletions

View File

@ -14,6 +14,7 @@ package org.openhab.binding.airvisualnode.internal;
import static org.openhab.binding.airvisualnode.internal.AirVisualNodeBindingConstants.*; import static org.openhab.binding.airvisualnode.internal.AirVisualNodeBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.airvisualnode.internal.handler.AirVisualNodeHandler; import org.openhab.binding.airvisualnode.internal.handler.AirVisualNodeHandler;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
@ -29,6 +30,7 @@ import org.osgi.service.component.annotations.Component;
* *
* @author Victor Antonovich - Initial contribution * @author Victor Antonovich - Initial contribution
*/ */
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.airvisualnode") @Component(service = ThingHandlerFactory.class, configurationPid = "binding.airvisualnode")
public class AirVisualNodeHandlerFactory extends BaseThingHandlerFactory { public class AirVisualNodeHandlerFactory extends BaseThingHandlerFactory {

View File

@ -12,22 +12,25 @@
*/ */
package org.openhab.binding.airvisualnode.internal.config; package org.openhab.binding.airvisualnode.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
* Configuration for AirVisual Node. * Configuration for AirVisual Node.
* *
* @author Victor Antonovich - Initial contribution * @author Victor Antonovich - Initial contribution
*/ */
@NonNullByDefault
public class AirVisualNodeConfig { public class AirVisualNodeConfig {
public static final String ADDRESS = "address"; public static final String ADDRESS = "address";
public String address; public String address = "";
public String username; public String username = "";
public String password; public String password = "";
public String share; public String share = "";
public long refresh; public long refresh;

View File

@ -20,6 +20,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.airvisualnode.internal.AirVisualNodeBindingConstants; import org.openhab.binding.airvisualnode.internal.AirVisualNodeBindingConstants;
import org.openhab.binding.airvisualnode.internal.config.AirVisualNodeConfig; import org.openhab.binding.airvisualnode.internal.config.AirVisualNodeConfig;
import org.openhab.core.config.discovery.AbstractDiscoveryService; import org.openhab.core.config.discovery.AbstractDiscoveryService;
@ -39,16 +41,18 @@ import jcifs.smb.SmbFile;
* *
* @author Victor Antonovich - Initial contribution * @author Victor Antonovich - Initial contribution
*/ */
@NonNullByDefault
@Component(service = DiscoveryService.class) @Component(service = DiscoveryService.class)
public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService { public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(AirVisualNodeDiscoveryService.class); private final Logger logger = LoggerFactory.getLogger(AirVisualNodeDiscoveryService.class);
private static final int REFRESH_MINUTES = 5;
public static final String AVISUAL_WORKGROUP_NAME = "MSHOME"; public static final String AVISUAL_WORKGROUP_NAME = "MSHOME";
private static final Pattern AVISUAL_NAME_PATTERN = Pattern.compile("^AVISUAL-([^/]+)$"); private static final Pattern AVISUAL_NAME_PATTERN = Pattern.compile("^AVISUAL-([^/]+)$");
private ScheduledFuture<?> backgroundDiscoveryFuture; private @Nullable ScheduledFuture<?> backgroundDiscoveryFuture;
public AirVisualNodeDiscoveryService() { public AirVisualNodeDiscoveryService() {
super(Collections.singleton(AirVisualNodeBindingConstants.THING_TYPE_AVNODE), 600, true); super(Collections.singleton(AirVisualNodeBindingConstants.THING_TYPE_AVNODE), 600, true);
@ -63,19 +67,20 @@ public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService {
@Override @Override
protected void startBackgroundDiscovery() { protected void startBackgroundDiscovery() {
logger.debug("Starting background discovery"); logger.debug("Starting background discovery");
backgroundDiscoveryFuture = scheduler.scheduleWithFixedDelay(this::scan, 0, 5, TimeUnit.MINUTES); ScheduledFuture<?> localDiscoveryFuture = backgroundDiscoveryFuture;
if (localDiscoveryFuture == null || localDiscoveryFuture.isCancelled()) {
backgroundDiscoveryFuture = scheduler.scheduleWithFixedDelay(this::scan, 0, REFRESH_MINUTES,
TimeUnit.MINUTES);
}
} }
@Override @Override
protected void stopBackgroundDiscovery() { protected void stopBackgroundDiscovery() {
logger.debug("Stopping background discovery"); logger.debug("Stopping background discovery");
cancelBackgroundDiscoveryFuture();
super.stopBackgroundDiscovery();
}
private void cancelBackgroundDiscoveryFuture() { ScheduledFuture<?> localDiscoveryFuture = backgroundDiscoveryFuture;
if (backgroundDiscoveryFuture != null && !backgroundDiscoveryFuture.isDone()) { if (localDiscoveryFuture != null) {
backgroundDiscoveryFuture.cancel(true); localDiscoveryFuture.cancel(true);
backgroundDiscoveryFuture = null; backgroundDiscoveryFuture = null;
} }
} }
@ -87,7 +92,7 @@ public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService {
String workgroupUrl = "smb://" + AVISUAL_WORKGROUP_NAME + "/"; String workgroupUrl = "smb://" + AVISUAL_WORKGROUP_NAME + "/";
workgroupMembers = new SmbFile(workgroupUrl).listFiles(); workgroupMembers = new SmbFile(workgroupUrl).listFiles();
} catch (IOException e) { } catch (IOException e) {
// Can't get workgroup member list logger.debug("IOException while trying to get workgroup member list", e);
return; return;
} }
@ -105,6 +110,10 @@ public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService {
// Extract the Node serial number from device name // Extract the Node serial number from device name
String nodeSerialNumber = m.group(1); String nodeSerialNumber = m.group(1);
if (nodeSerialNumber != null) {
logger.debug("Extracting the Node serial number failed");
return;
}
// The Node Thing UID is serial number converted to lower case // The Node Thing UID is serial number converted to lower case
ThingUID thingUID = new ThingUID(AirVisualNodeBindingConstants.THING_TYPE_AVNODE, ThingUID thingUID = new ThingUID(AirVisualNodeBindingConstants.THING_TYPE_AVNODE,
nodeSerialNumber.toLowerCase()); nodeSerialNumber.toLowerCase());
@ -119,14 +128,19 @@ public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService {
// Create discovery result // Create discovery result
String nodeAddress = nodeNbtAddress.getInetAddress().getHostAddress(); String nodeAddress = nodeNbtAddress.getInetAddress().getHostAddress();
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID) if (nodeAddress != null) {
.withProperty(AirVisualNodeConfig.ADDRESS, nodeAddress) DiscoveryResult result = DiscoveryResultBuilder.create(thingUID)
.withRepresentationProperty(AirVisualNodeConfig.ADDRESS) .withProperty(AirVisualNodeConfig.ADDRESS, nodeAddress)
.withLabel("AirVisual Node (" + nodeSerialNumber + ")").build(); .withRepresentationProperty(AirVisualNodeConfig.ADDRESS)
thingDiscovered(result); .withLabel("AirVisual Node (" + nodeSerialNumber + ")").build();
thingDiscovered(result);
} else {
logger.debug("Getting the node address from the host failed");
}
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
logger.debug("The Node address resolving failed ", e); logger.debug("The Node address resolving failed ", e);
} }
} }
} }
} }

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json; package org.openhab.binding.airvisualnode.internal.dto;
/** /**
* Date and time / timestamp data. * Date and time / timestamp data.

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json; package org.openhab.binding.airvisualnode.internal.dto;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;

View File

@ -10,11 +10,11 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json; package org.openhab.binding.airvisualnode.internal.dto;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.airvisualnode.internal.json.airvisual.Settings; import org.openhab.binding.airvisualnode.internal.dto.airvisual.Settings;
import org.openhab.binding.airvisualnode.internal.json.airvisual.Status; import org.openhab.binding.airvisualnode.internal.dto.airvisual.Status;
/** /**
* Interface for AirVisual and AirVisual Pro models * Interface for AirVisual and AirVisual Pro models

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json; package org.openhab.binding.airvisualnode.internal.dto;
/** /**
* Power saving time data. * Power saving time data.

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json; package org.openhab.binding.airvisualnode.internal.dto;
/** /**
* Power saving time slot data. * Power saving time slot data.

View File

@ -10,9 +10,9 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisual; package org.openhab.binding.airvisualnode.internal.dto.airvisual;
import org.openhab.binding.airvisualnode.internal.json.MeasurementsInterface; import org.openhab.binding.airvisualnode.internal.dto.MeasurementsInterface;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,17 +10,19 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisual; package org.openhab.binding.airvisualnode.internal.dto.airvisual;
import org.openhab.binding.airvisualnode.internal.json.DateAndTime; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.airvisualnode.internal.json.MeasurementsInterface; import org.openhab.binding.airvisualnode.internal.dto.DateAndTime;
import org.openhab.binding.airvisualnode.internal.json.NodeDataInterface; import org.openhab.binding.airvisualnode.internal.dto.MeasurementsInterface;
import org.openhab.binding.airvisualnode.internal.dto.NodeDataInterface;
/** /**
* Top level object for AirVisual Node JSON data. * Top level object for AirVisual Node JSON data.
* *
* @author Victor Antonovich - Initial contribution * @author Victor Antonovich - Initial contribution
*/ */
@NonNullByDefault
public class NodeData implements NodeDataInterface { public class NodeData implements NodeDataInterface {
private DateAndTime dateAndTime; private DateAndTime dateAndTime;

View File

@ -10,12 +10,12 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisual; package org.openhab.binding.airvisualnode.internal.dto.airvisual;
import java.util.List; import java.util.List;
import org.openhab.binding.airvisualnode.internal.json.PowerSavingTime; import org.openhab.binding.airvisualnode.internal.dto.PowerSavingTime;
import org.openhab.binding.airvisualnode.internal.json.PowerSavingTimeSlot; import org.openhab.binding.airvisualnode.internal.dto.PowerSavingTimeSlot;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisual; package org.openhab.binding.airvisualnode.internal.dto.airvisual;
/** /**
* Settings data. * Settings data.

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisual; package org.openhab.binding.airvisualnode.internal.dto.airvisual;
/** /**
* Status data. * Status data.

View File

@ -10,9 +10,9 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
import org.openhab.binding.airvisualnode.internal.json.MeasurementsInterface; import org.openhab.binding.airvisualnode.internal.dto.MeasurementsInterface;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
@ -54,7 +54,6 @@ public class Measurements implements MeasurementsInterface {
public Measurements(int co2Ppm, int humidityRH, int pm25AQICN, int pm25AQIUS, float pm01Ugm3, float pm10Ugm3, public Measurements(int co2Ppm, int humidityRH, int pm25AQICN, int pm25AQIUS, float pm01Ugm3, float pm10Ugm3,
float pm25Ugm3, float temperatureC, float temperatureF, int vocPpb) { float pm25Ugm3, float temperatureC, float temperatureF, int vocPpb) {
this.co2Ppm = co2Ppm; this.co2Ppm = co2Ppm;
this.humidityRH = humidityRH; this.humidityRH = humidityRH;
this.pm25AQICN = pm25AQICN; this.pm25AQICN = pm25AQICN;

View File

@ -10,12 +10,12 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
import java.util.List; import java.util.List;
import org.openhab.binding.airvisualnode.internal.json.PowerSavingTime; import org.openhab.binding.airvisualnode.internal.dto.PowerSavingTime;
import org.openhab.binding.airvisualnode.internal.json.PowerSavingTimeSlot; import org.openhab.binding.airvisualnode.internal.dto.PowerSavingTimeSlot;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,21 +10,23 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
import java.util.List; import java.util.List;
import org.openhab.binding.airvisualnode.internal.json.DateAndTime; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.airvisualnode.internal.json.MeasurementsInterface; import org.openhab.binding.airvisualnode.internal.dto.DateAndTime;
import org.openhab.binding.airvisualnode.internal.json.NodeDataInterface; import org.openhab.binding.airvisualnode.internal.dto.MeasurementsInterface;
import org.openhab.binding.airvisualnode.internal.json.airvisual.Settings; import org.openhab.binding.airvisualnode.internal.dto.NodeDataInterface;
import org.openhab.binding.airvisualnode.internal.json.airvisual.Status; import org.openhab.binding.airvisualnode.internal.dto.airvisual.Settings;
import org.openhab.binding.airvisualnode.internal.dto.airvisual.Status;
/** /**
* Top level object for AirVisual Node JSON data. * Top level object for AirVisual Node JSON data.
* *
* @author Victor Antonovich - Initial contribution * @author Victor Antonovich - Initial contribution
*/ */
@NonNullByDefault
public class ProNodeData implements NodeDataInterface { public class ProNodeData implements NodeDataInterface {
private DateAndTime dateAndTime; private DateAndTime dateAndTime;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
/** /**
* Sensor Usage/Life data * Sensor Usage/Life data

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
/** /**
* Sensor Operating Mode * Sensor Operating Mode

View File

@ -10,9 +10,9 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
import org.openhab.binding.airvisualnode.internal.json.airvisual.PowerSaving; import org.openhab.binding.airvisualnode.internal.dto.airvisual.PowerSaving;
/** /**
* Settings data. * Settings data.
@ -41,7 +41,6 @@ public class Settings {
boolean isIndoor, boolean isLcdOn, boolean isNetworkTime, boolean isTemperatureCelsius, String language, boolean isIndoor, boolean isLcdOn, boolean isNetworkTime, boolean isTemperatureCelsius, String language,
int lcdBrightness, String nodeName, PowerSaving powerSaving, SensorMode sensorMode, String speedUnit, int lcdBrightness, String nodeName, PowerSaving powerSaving, SensorMode sensorMode, String speedUnit,
String timezone) { String timezone) {
this.followMode = followMode; this.followMode = followMode;
this.followedStation = followedStation; this.followedStation = followedStation;
this.isAqiUsa = isAqiUsa; this.isAqiUsa = isAqiUsa;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.airvisualnode.internal.json.airvisualpro; package org.openhab.binding.airvisualnode.internal.dto.airvisualpro;
/** /**
* Status data. * Status data.

View File

@ -35,11 +35,13 @@ import java.util.Map;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.airvisualnode.internal.config.AirVisualNodeConfig; import org.openhab.binding.airvisualnode.internal.config.AirVisualNodeConfig;
import org.openhab.binding.airvisualnode.internal.json.MeasurementsInterface; import org.openhab.binding.airvisualnode.internal.dto.MeasurementsInterface;
import org.openhab.binding.airvisualnode.internal.json.NodeDataInterface; import org.openhab.binding.airvisualnode.internal.dto.NodeDataInterface;
import org.openhab.binding.airvisualnode.internal.json.airvisual.NodeData; import org.openhab.binding.airvisualnode.internal.dto.airvisual.NodeData;
import org.openhab.binding.airvisualnode.internal.json.airvisualpro.ProNodeData; import org.openhab.binding.airvisualnode.internal.dto.airvisualpro.ProNodeData;
import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
@ -71,29 +73,23 @@ import jcifs.smb.SmbFileInputStream;
* *
* @author Victor Antonovich - Initial contribution * @author Victor Antonovich - Initial contribution
*/ */
@NonNullByDefault
public class AirVisualNodeHandler extends BaseThingHandler { public class AirVisualNodeHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(AirVisualNodeHandler.class); private final Logger logger = LoggerFactory.getLogger(AirVisualNodeHandler.class);
public static final String NODE_JSON_FILE = "latest_config_measurements.json"; public static final String NODE_JSON_FILE = "latest_config_measurements.json";
private static final long DELAY_IN_MS = 500;
private final Gson gson; private final Gson gson;
private @Nullable ScheduledFuture<?> pollFuture;
private ScheduledFuture<?> pollFuture;
private long refreshInterval; private long refreshInterval;
private String nodeAddress = "";
private String nodeAddress; private String nodeUsername = "";
private String nodePassword = "";
private String nodeUsername; private String nodeShareName = "";
private @Nullable NodeDataInterface nodeData;
private String nodePassword; private boolean isProVersion = false;
private String nodeShareName;
private NodeDataInterface nodeData;
private boolean isProVersion;
public AirVisualNodeHandler(Thing thing) { public AirVisualNodeHandler(Thing thing) {
super(thing); super(thing);
@ -106,22 +102,19 @@ public class AirVisualNodeHandler extends BaseThingHandler {
AirVisualNodeConfig config = getConfigAs(AirVisualNodeConfig.class); AirVisualNodeConfig config = getConfigAs(AirVisualNodeConfig.class);
if (config.address == null) { if (config.address.isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Node address must be set"); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Node address must be set");
return; return;
} }
this.nodeAddress = config.address; if (config.password.isBlank()) {
this.nodeUsername = config.username;
if (config.password == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Node password must be set"); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Node password must be set");
return; return;
} }
this.nodeAddress = config.address;
this.nodeUsername = config.username;
this.nodePassword = config.password; this.nodePassword = config.password;
this.nodeShareName = config.share; this.nodeShareName = config.share;
this.refreshInterval = config.refresh * 1000L; this.refreshInterval = config.refresh * 1000L;
try { try {
@ -141,10 +134,17 @@ public class AirVisualNodeHandler extends BaseThingHandler {
private void removeProChannels() { private void removeProChannels() {
List<Channel> channels = new ArrayList<>(getThing().getChannels()); List<Channel> channels = new ArrayList<>(getThing().getChannels());
channels.removeIf(channel -> channel.getLabel().equals("PM0.1") || channel.getLabel().equals("PM10")); channels.removeIf(channel -> isProChannel(channel.getLabel()));
replaceChannels(channels); replaceChannels(channels);
} }
private boolean isProChannel(@Nullable String channelLabel) {
if (channelLabel == null || channelLabel.isBlank()) {
return false;
}
return "PM0.1".equals(channelLabel) || "PM10".equals(channelLabel);
}
private void replaceChannels(List<Channel> channels) { private void replaceChannels(List<Channel> channels) {
ThingBuilder thingBuilder = editThing(); ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(channels); thingBuilder.withChannels(channels);
@ -173,14 +173,15 @@ public class AirVisualNodeHandler extends BaseThingHandler {
} }
private synchronized void stopPoll() { private synchronized void stopPoll() {
if (pollFuture != null && !pollFuture.isCancelled()) { ScheduledFuture<?> localFuture = pollFuture;
pollFuture.cancel(false); if (localFuture != null) {
localFuture.cancel(false);
} }
} }
private synchronized void schedulePoll() { private synchronized void schedulePoll() {
logger.debug("Scheduling poll for 500ms out, then every {} ms", refreshInterval); logger.debug("Scheduling poll for {}}ms out, then every {} ms", DELAY_IN_MS, refreshInterval);
pollFuture = scheduler.scheduleWithFixedDelay(this::poll, 500, refreshInterval, TimeUnit.MILLISECONDS); pollFuture = scheduler.scheduleWithFixedDelay(this::poll, DELAY_IN_MS, refreshInterval, TimeUnit.MILLISECONDS);
} }
private void poll() { private void poll() {
@ -203,8 +204,9 @@ public class AirVisualNodeHandler extends BaseThingHandler {
} else { } else {
currentNodeData = gson.fromJson(jsonData, NodeData.class); currentNodeData = gson.fromJson(jsonData, NodeData.class);
} }
NodeDataInterface localNodeDate = nodeData;
if (nodeData == null || currentNodeData.getStatus().getDatetime() > nodeData.getStatus().getDatetime()) { if (localNodeDate == null
|| currentNodeData.getStatus().getDatetime() > localNodeDate.getStatus().getDatetime()) {
nodeData = currentNodeData; nodeData = currentNodeData;
// Update all channels from the updated Node data // Update all channels from the updated Node data
for (Channel channel : getThing().getChannels()) { for (Channel channel : getThing().getChannels()) {
@ -222,8 +224,9 @@ public class AirVisualNodeHandler extends BaseThingHandler {
} }
private void updateChannel(String channelId, boolean force) { private void updateChannel(String channelId, boolean force) {
if (nodeData != null && (force || isLinked(channelId))) { NodeDataInterface localnodeData = nodeData;
State state = getChannelState(channelId, nodeData); if (localnodeData != null && (force || isLinked(channelId))) {
State state = getChannelState(channelId, localnodeData);
logger.debug("Update channel {} with state {}", channelId, state); logger.debug("Update channel {} with state {}", channelId, state);
updateState(channelId, state); updateState(channelId, state);
} }