[melcloud] Improve null handling (#17295)

* Add null annotations

Signed-off-by: Leo Siepel <leosiepel@gmail.com>
This commit is contained in:
lsiepel 2024-09-09 21:21:37 +02:00 committed by Leo Siepel
parent d5ad854aac
commit 600ca69c94
25 changed files with 154 additions and 128 deletions

View File

@ -17,6 +17,7 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingTypeUID;
/** /**
@ -26,6 +27,7 @@ import org.openhab.core.thing.ThingTypeUID;
* @author Luca Calcaterra - Initial contribution * @author Luca Calcaterra - Initial contribution
* @author Wietse van Buitenen - Added heatpump device * @author Wietse van Buitenen - Added heatpump device
*/ */
@NonNullByDefault
public class MelCloudBindingConstants { public class MelCloudBindingConstants {
private static final String BINDING_ID = "melcloud"; private static final String BINDING_ID = "melcloud";

View File

@ -14,6 +14,7 @@ package org.openhab.binding.melcloud.internal;
import static org.openhab.binding.melcloud.internal.MelCloudBindingConstants.*; import static org.openhab.binding.melcloud.internal.MelCloudBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.melcloud.internal.handler.MelCloudAccountHandler; import org.openhab.binding.melcloud.internal.handler.MelCloudAccountHandler;
import org.openhab.binding.melcloud.internal.handler.MelCloudDeviceHandler; import org.openhab.binding.melcloud.internal.handler.MelCloudDeviceHandler;
@ -33,6 +34,7 @@ import org.osgi.service.component.annotations.Component;
* @author Luca Calcaterra - Initial contribution * @author Luca Calcaterra - Initial contribution
* @author Wietse van Buitenen - Added heatpump device * @author Wietse van Buitenen - Added heatpump device
*/ */
@NonNullByDefault
@Component(configurationPid = "binding.melcloud", service = ThingHandlerFactory.class) @Component(configurationPid = "binding.melcloud", service = ThingHandlerFactory.class)
public class MelCloudHandlerFactory extends BaseThingHandlerFactory { public class MelCloudHandlerFactory extends BaseThingHandlerFactory {

View File

@ -19,13 +19,15 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import org.openhab.binding.melcloud.internal.api.json.Device; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.melcloud.internal.api.json.DeviceStatus; import org.openhab.binding.melcloud.internal.api.dto.Device;
import org.openhab.binding.melcloud.internal.api.json.HeatpumpDeviceStatus; import org.openhab.binding.melcloud.internal.api.dto.DeviceStatus;
import org.openhab.binding.melcloud.internal.api.json.ListDevicesResponse; import org.openhab.binding.melcloud.internal.api.dto.HeatpumpDeviceStatus;
import org.openhab.binding.melcloud.internal.api.json.LoginClientResponse; import org.openhab.binding.melcloud.internal.api.dto.ListDevicesResponse;
import org.openhab.binding.melcloud.internal.api.dto.LoginClientResponse;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException;
import org.openhab.core.io.net.http.HttpUtil; import org.openhab.core.io.net.http.HttpUtil;
@ -45,6 +47,7 @@ import com.google.gson.JsonSyntaxException;
* @author Pauli Anttila - Refactoring * @author Pauli Anttila - Refactoring
* @author Wietse van Buitenen - Return all devices, added heatpump device * @author Wietse van Buitenen - Return all devices, added heatpump device
*/ */
@NonNullByDefault
public class MelCloudConnection { public class MelCloudConnection {
private static final String LOGIN_URL = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin"; private static final String LOGIN_URL = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin";
@ -54,18 +57,18 @@ public class MelCloudConnection {
private static final int TIMEOUT_MILLISECONDS = 10000; private static final int TIMEOUT_MILLISECONDS = 10000;
// Gson objects are safe to share across threads and are somewhat expensive to construct. Use a single instance. // Gson objects are safe to share across threads and are somewhat expensive to construct. Use a single instance.
private static final Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation() private static final Gson GSON = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
private final Logger logger = LoggerFactory.getLogger(MelCloudConnection.class); private final Logger logger = LoggerFactory.getLogger(MelCloudConnection.class);
private boolean isConnected = false; private boolean isConnected = false;
private String sessionKey; private String sessionKey = "";
public void login(String username, String password, int languageId) public void login(String username, String password, int languageId)
throws MelCloudCommException, MelCloudLoginException { throws MelCloudCommException, MelCloudLoginException {
setConnected(false); setConnected(false);
sessionKey = null; sessionKey = "";
JsonObject jsonReq = new JsonObject(); JsonObject jsonReq = new JsonObject();
jsonReq.addProperty("Email", username); jsonReq.addProperty("Email", username);
jsonReq.addProperty("Password", password); jsonReq.addProperty("Password", password);
@ -79,7 +82,7 @@ public class MelCloudConnection {
String loginResponse = HttpUtil.executeUrl("POST", LOGIN_URL, null, data, "application/json", String loginResponse = HttpUtil.executeUrl("POST", LOGIN_URL, null, data, "application/json",
TIMEOUT_MILLISECONDS); TIMEOUT_MILLISECONDS);
logger.debug("Login response: {}", loginResponse); logger.debug("Login response: {}", loginResponse);
LoginClientResponse resp = gson.fromJson(loginResponse, LoginClientResponse.class); LoginClientResponse resp = Objects.requireNonNull(GSON.fromJson(loginResponse, LoginClientResponse.class));
if (resp.getErrorId() != null) { if (resp.getErrorId() != null) {
String errorMsg = String.format("Login failed, error code: %s", resp.getErrorId()); String errorMsg = String.format("Login failed, error code: %s", resp.getErrorId());
if (resp.getErrorMessage() != null) { if (resp.getErrorMessage() != null) {
@ -101,7 +104,7 @@ public class MelCloudConnection {
TIMEOUT_MILLISECONDS); TIMEOUT_MILLISECONDS);
logger.debug("Device list response: {}", response); logger.debug("Device list response: {}", response);
List<Device> devices = new ArrayList<>(); List<Device> devices = new ArrayList<>();
ListDevicesResponse[] buildings = gson.fromJson(response, ListDevicesResponse[].class); ListDevicesResponse[] buildings = GSON.fromJson(response, ListDevicesResponse[].class);
Arrays.asList(buildings).forEach(building -> { Arrays.asList(buildings).forEach(building -> {
if (building.getStructure().getDevices() != null) { if (building.getStructure().getDevices() != null) {
devices.addAll(building.getStructure().getDevices()); devices.addAll(building.getStructure().getDevices());
@ -137,7 +140,7 @@ public class MelCloudConnection {
try { try {
String response = HttpUtil.executeUrl("GET", url, getHeaderProperties(), null, null, TIMEOUT_MILLISECONDS); String response = HttpUtil.executeUrl("GET", url, getHeaderProperties(), null, null, TIMEOUT_MILLISECONDS);
logger.debug("Device status response: {}", response); logger.debug("Device status response: {}", response);
return gson.fromJson(response, DeviceStatus.class); return Objects.requireNonNull(GSON.fromJson(response, DeviceStatus.class));
} catch (IOException | JsonSyntaxException e) { } catch (IOException | JsonSyntaxException e) {
setConnected(false); setConnected(false);
throw new MelCloudCommException("Error occurred during device status fetch", e); throw new MelCloudCommException("Error occurred during device status fetch", e);
@ -146,14 +149,14 @@ public class MelCloudConnection {
public DeviceStatus sendDeviceStatus(DeviceStatus deviceStatus) throws MelCloudCommException { public DeviceStatus sendDeviceStatus(DeviceStatus deviceStatus) throws MelCloudCommException {
assertConnected(); assertConnected();
String content = gson.toJson(deviceStatus, DeviceStatus.class); String content = GSON.toJson(deviceStatus, DeviceStatus.class);
logger.debug("Sending device status: {}", content); logger.debug("Sending device status: {}", content);
InputStream data = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); InputStream data = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
try { try {
String response = HttpUtil.executeUrl("POST", DEVICE_URL + "/SetAta", getHeaderProperties(), data, String response = HttpUtil.executeUrl("POST", DEVICE_URL + "/SetAta", getHeaderProperties(), data,
"application/json", TIMEOUT_MILLISECONDS); "application/json", TIMEOUT_MILLISECONDS);
logger.debug("Device status sending response: {}", response); logger.debug("Device status sending response: {}", response);
return gson.fromJson(response, DeviceStatus.class); return Objects.requireNonNull(GSON.fromJson(response, DeviceStatus.class));
} catch (IOException | JsonSyntaxException e) { } catch (IOException | JsonSyntaxException e) {
setConnected(false); setConnected(false);
throw new MelCloudCommException("Error occurred during device command sending", e); throw new MelCloudCommException("Error occurred during device command sending", e);
@ -166,7 +169,7 @@ public class MelCloudConnection {
try { try {
String response = HttpUtil.executeUrl("GET", url, getHeaderProperties(), null, null, TIMEOUT_MILLISECONDS); String response = HttpUtil.executeUrl("GET", url, getHeaderProperties(), null, null, TIMEOUT_MILLISECONDS);
logger.debug("Device heatpump status response: {}", response); logger.debug("Device heatpump status response: {}", response);
return gson.fromJson(response, HeatpumpDeviceStatus.class); return Objects.requireNonNull(GSON.fromJson(response, HeatpumpDeviceStatus.class));
} catch (IOException | JsonSyntaxException e) { } catch (IOException | JsonSyntaxException e) {
setConnected(false); setConnected(false);
throw new MelCloudCommException("Error occurred during heatpump device status fetch", e); throw new MelCloudCommException("Error occurred during heatpump device status fetch", e);
@ -176,14 +179,14 @@ public class MelCloudConnection {
public HeatpumpDeviceStatus sendHeatpumpDeviceStatus(HeatpumpDeviceStatus heatpumpDeviceStatus) public HeatpumpDeviceStatus sendHeatpumpDeviceStatus(HeatpumpDeviceStatus heatpumpDeviceStatus)
throws MelCloudCommException { throws MelCloudCommException {
assertConnected(); assertConnected();
String content = gson.toJson(heatpumpDeviceStatus, HeatpumpDeviceStatus.class); String content = GSON.toJson(heatpumpDeviceStatus, HeatpumpDeviceStatus.class);
logger.debug("Sending heatpump device status: {}", content); logger.debug("Sending heatpump device status: {}", content);
InputStream data = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); InputStream data = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
try { try {
String response = HttpUtil.executeUrl("POST", DEVICE_URL + "/SetAtw", getHeaderProperties(), data, String response = HttpUtil.executeUrl("POST", DEVICE_URL + "/SetAtw", getHeaderProperties(), data,
"application/json", TIMEOUT_MILLISECONDS); "application/json", TIMEOUT_MILLISECONDS);
logger.debug("Device heatpump status sending response: {}", response); logger.debug("Device heatpump status sending response: {}", response);
return gson.fromJson(response, HeatpumpDeviceStatus.class); return Objects.requireNonNull(GSON.fromJson(response, HeatpumpDeviceStatus.class));
} catch (IOException | JsonSyntaxException e) { } catch (IOException | JsonSyntaxException e) {
setConnected(false); setConnected(false);
throw new MelCloudCommException("Error occurred during heatpump device command sending", e); throw new MelCloudCommException("Error occurred during heatpump device command sending", e);

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.security.Permissions; import java.security.Permissions;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
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.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.melcloud.internal.api.json; package org.openhab.binding.melcloud.internal.api.dto;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;

View File

@ -12,17 +12,21 @@
*/ */
package org.openhab.binding.melcloud.internal.config; package org.openhab.binding.melcloud.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/** /**
* Config class for an A.C. device. * Config class for an A.C. device.
* *
* @author Pauli Anttila - Initial Contribution * @author Pauli Anttila - Initial Contribution
* *
*/ */
@NonNullByDefault
public class AcDeviceConfig { public class AcDeviceConfig {
public Integer deviceID; public Integer deviceID = 0;
public Integer buildingID; public @Nullable Integer buildingID;
public Integer pollingInterval; public Integer pollingInterval = 360;
@Override @Override
public String toString() { public String toString() {

View File

@ -12,17 +12,20 @@
*/ */
package org.openhab.binding.melcloud.internal.config; package org.openhab.binding.melcloud.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
* Config class for MELCloud account parameters. * Config class for MELCloud account parameters.
* *
* @author Pauli Anttila - Initial Contribution * @author Pauli Anttila - Initial Contribution
* *
*/ */
@NonNullByDefault
public class AccountConfig { public class AccountConfig {
public String username; public String username = "";
public String password; public String password = "";
public int language; public int language = 0;
@Override @Override
public String toString() { public String toString() {
@ -30,9 +33,6 @@ public class AccountConfig {
} }
private String getPasswordForPrinting() { private String getPasswordForPrinting() {
if (password != null) { return password.isEmpty() ? "<empty>" : "*********";
return password.isEmpty() ? "<empty>" : "*********";
}
return "<null>";
} }
} }

View File

@ -12,16 +12,20 @@
*/ */
package org.openhab.binding.melcloud.internal.config; package org.openhab.binding.melcloud.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/** /**
* Config class for a Heatpump device. * Config class for a Heatpump device.
* *
* @author Wietse van Buitenen - Initial Contribution * @author Wietse van Buitenen - Initial Contribution
* *
*/ */
@NonNullByDefault
public class HeatpumpDeviceConfig { public class HeatpumpDeviceConfig {
public Integer deviceID; public Integer deviceID = 0;
public Integer buildingID; public @Nullable Integer buildingID;
public Integer pollingInterval; public Integer pollingInterval = 360;
@Override @Override
public String toString() { public String toString() {

View File

@ -20,9 +20,10 @@ 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.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.melcloud.internal.MelCloudBindingConstants; import org.openhab.binding.melcloud.internal.MelCloudBindingConstants;
import org.openhab.binding.melcloud.internal.api.json.Device; import org.openhab.binding.melcloud.internal.api.dto.Device;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException;
import org.openhab.binding.melcloud.internal.handler.MelCloudAccountHandler; import org.openhab.binding.melcloud.internal.handler.MelCloudAccountHandler;
@ -43,14 +44,15 @@ import org.slf4j.LoggerFactory;
* @author Pauli Anttila - Refactoring * @author Pauli Anttila - Refactoring
* @author Wietse van Buitenen - Check device type, added heatpump device * @author Wietse van Buitenen - Check device type, added heatpump device
*/ */
@NonNullByDefault
@Component(scope = ServiceScope.PROTOTYPE, service = MelCloudDiscoveryService.class) @Component(scope = ServiceScope.PROTOTYPE, service = MelCloudDiscoveryService.class)
public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryService<@NonNull MelCloudAccountHandler> { public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryService<MelCloudAccountHandler> {
private final Logger logger = LoggerFactory.getLogger(MelCloudDiscoveryService.class); private final Logger logger = LoggerFactory.getLogger(MelCloudDiscoveryService.class);
private static final String PROPERTY_DEVICE_ID = "deviceID"; private static final String PROPERTY_DEVICE_ID = "deviceID";
private static final int DISCOVER_TIMEOUT_SECONDS = 10; private static final int DISCOVER_TIMEOUT_SECONDS = 10;
private ScheduledFuture<?> scanTask; private @Nullable ScheduledFuture<?> scanTask;
/** /**
* Creates a MelCloudDiscoveryService with enabled autostart. * Creates a MelCloudDiscoveryService with enabled autostart.
@ -67,7 +69,8 @@ public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryServi
@Override @Override
protected void startScan() { protected void startScan() {
if (this.scanTask != null) { ScheduledFuture<?> scanTask = this.scanTask;
if (scanTask != null) {
scanTask.cancel(true); scanTask.cancel(true);
} }
this.scanTask = scheduler.schedule(() -> discoverDevices(), 0, TimeUnit.SECONDS); this.scanTask = scheduler.schedule(() -> discoverDevices(), 0, TimeUnit.SECONDS);
@ -77,8 +80,9 @@ public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryServi
protected void stopScan() { protected void stopScan() {
super.stopScan(); super.stopScan();
if (this.scanTask != null) { ScheduledFuture<?> scanTask = this.scanTask;
this.scanTask.cancel(true); if (scanTask != null) {
scanTask.cancel(true);
this.scanTask = null; this.scanTask = null;
} }
} }
@ -88,7 +92,7 @@ public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryServi
try { try {
List<Device> deviceList = thingHandler.getDeviceList(); List<Device> deviceList = thingHandler.getDeviceList();
if (deviceList == null) { if (deviceList.isEmpty()) {
logger.debug("No devices found"); logger.debug("No devices found");
} else { } else {
ThingUID bridgeUID = thingHandler.getThing().getUID(); ThingUID bridgeUID = thingHandler.getThing().getUID();

View File

@ -12,11 +12,14 @@
*/ */
package org.openhab.binding.melcloud.internal.exceptions; package org.openhab.binding.melcloud.internal.exceptions;
import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
* Exception to encapsulate any issues communicating with MELCloud. * Exception to encapsulate any issues communicating with MELCloud.
* *
* @author Pauli Anttila - Initial Contribution * @author Pauli Anttila - Initial Contribution
*/ */
@NonNullByDefault
public class MelCloudCommException extends Exception { public class MelCloudCommException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -12,11 +12,14 @@
*/ */
package org.openhab.binding.melcloud.internal.exceptions; package org.openhab.binding.melcloud.internal.exceptions;
import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
* Exception to encapsulate any login issues with MELCloud. * Exception to encapsulate any login issues with MELCloud.
* *
* @author Pauli Anttila - Initial Contribution * @author Pauli Anttila - Initial Contribution
*/ */
@NonNullByDefault
public class MelCloudLoginException extends Exception { public class MelCloudLoginException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -15,15 +15,16 @@ package org.openhab.binding.melcloud.internal.handler;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
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.melcloud.internal.api.MelCloudConnection; import org.openhab.binding.melcloud.internal.api.MelCloudConnection;
import org.openhab.binding.melcloud.internal.api.json.Device; import org.openhab.binding.melcloud.internal.api.dto.Device;
import org.openhab.binding.melcloud.internal.api.json.DeviceStatus; import org.openhab.binding.melcloud.internal.api.dto.DeviceStatus;
import org.openhab.binding.melcloud.internal.api.json.HeatpumpDeviceStatus; import org.openhab.binding.melcloud.internal.api.dto.HeatpumpDeviceStatus;
import org.openhab.binding.melcloud.internal.config.AccountConfig; import org.openhab.binding.melcloud.internal.config.AccountConfig;
import org.openhab.binding.melcloud.internal.discovery.MelCloudDiscoveryService; import org.openhab.binding.melcloud.internal.discovery.MelCloudDiscoveryService;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException;
@ -47,14 +48,15 @@ import org.slf4j.LoggerFactory;
* @author Pauli Anttila - Refactoring * @author Pauli Anttila - Refactoring
* @author Wietse van Buitenen - Return all devices, added heatpump device * @author Wietse van Buitenen - Return all devices, added heatpump device
*/ */
@NonNullByDefault
public class MelCloudAccountHandler extends BaseBridgeHandler { public class MelCloudAccountHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(MelCloudAccountHandler.class); private final Logger logger = LoggerFactory.getLogger(MelCloudAccountHandler.class);
private MelCloudConnection connection; private MelCloudConnection connection = new MelCloudConnection();
private List<Device> devices; private List<Device> devices = Collections.emptyList();
private ScheduledFuture<?> connectionCheckTask; private @Nullable ScheduledFuture<?> connectionCheckTask;
private AccountConfig config; private AccountConfig config = new AccountConfig();
private boolean loginCredentialError; private boolean loginCredentialError = false;
public MelCloudAccountHandler(Bridge bridge) { public MelCloudAccountHandler(Bridge bridge) {
super(bridge); super(bridge);
@ -69,8 +71,6 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
public void initialize() { public void initialize() {
logger.debug("Initializing MELCloud account handler."); logger.debug("Initializing MELCloud account handler.");
config = getConfigAs(AccountConfig.class); config = getConfigAs(AccountConfig.class);
connection = new MelCloudConnection();
devices = Collections.emptyList();
loginCredentialError = false; loginCredentialError = false;
startConnectionCheck(); startConnectionCheck();
} }
@ -79,9 +79,7 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
public void dispose() { public void dispose() {
logger.debug("Running dispose()"); logger.debug("Running dispose()");
stopConnectionCheck(); stopConnectionCheck();
connection = null;
devices = Collections.emptyList(); devices = Collections.emptyList();
config = null;
} }
@Override @Override
@ -102,6 +100,7 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
throw new MelCloudLoginException("Connection to MELCloud can't be opened because of wrong credentials"); throw new MelCloudLoginException("Connection to MELCloud can't be opened because of wrong credentials");
} }
logger.debug("Initializing connection to MELCloud"); logger.debug("Initializing connection to MELCloud");
updateStatus(ThingStatus.OFFLINE); updateStatus(ThingStatus.OFFLINE);
try { try {
connection.login(config.username, config.password, config.language); connection.login(config.username, config.password, config.language);
@ -139,10 +138,10 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
} }
} }
public DeviceStatus fetchDeviceStatus(int deviceId, Optional<Integer> buildingId) public DeviceStatus fetchDeviceStatus(int deviceId, @Nullable Integer buildingId)
throws MelCloudCommException, MelCloudLoginException { throws MelCloudCommException, MelCloudLoginException {
connectIfNotConnected(); connectIfNotConnected();
int bid = buildingId.orElse(findBuildingId(deviceId)); int bid = buildingId != null ? buildingId : findBuildingId(deviceId);
try { try {
return connection.fetchDeviceStatus(deviceId, bid); return connection.fetchDeviceStatus(deviceId, bid);
@ -165,10 +164,10 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
} }
} }
public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, Optional<Integer> buildingId) public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, @Nullable Integer buildingId)
throws MelCloudCommException, MelCloudLoginException { throws MelCloudCommException, MelCloudLoginException {
connectIfNotConnected(); connectIfNotConnected();
int bid = buildingId.orElse(findBuildingId(deviceId)); int bid = buildingId != null ? buildingId : findBuildingId(deviceId);
try { try {
return connection.fetchHeatpumpDeviceStatus(deviceId, bid); return connection.fetchHeatpumpDeviceStatus(deviceId, bid);
@ -180,15 +179,13 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
} }
private int findBuildingId(int deviceId) throws MelCloudCommException { private int findBuildingId(int deviceId) throws MelCloudCommException {
if (devices != null) { return devices.stream().filter(d -> d.getDeviceID() == deviceId).findFirst().orElseThrow(
return devices.stream().filter(d -> d.getDeviceID() == deviceId).findFirst().orElseThrow( () -> new MelCloudCommException(String.format("Can't find building id for device id %s", deviceId)))
() -> new MelCloudCommException(String.format("Can't find building id for device id %s", deviceId))) .getBuildingID();
.getBuildingID();
}
throw new MelCloudCommException(String.format("Can't find building id for device id %s", deviceId));
} }
private void startConnectionCheck() { private void startConnectionCheck() {
ScheduledFuture<?> connectionCheckTask = this.connectionCheckTask;
if (connectionCheckTask == null || connectionCheckTask.isCancelled()) { if (connectionCheckTask == null || connectionCheckTask.isCancelled()) {
logger.debug("Start periodic connection check"); logger.debug("Start periodic connection check");
Runnable runnable = () -> { Runnable runnable = () -> {
@ -207,17 +204,18 @@ public class MelCloudAccountHandler extends BaseBridgeHandler {
} }
} }
}; };
connectionCheckTask = scheduler.scheduleWithFixedDelay(runnable, 0, 300, TimeUnit.SECONDS); this.connectionCheckTask = scheduler.scheduleWithFixedDelay(runnable, 0, 300, TimeUnit.SECONDS);
} else { } else {
logger.debug("Connection check task already running"); logger.debug("Connection check task already running");
} }
} }
private void stopConnectionCheck() { private void stopConnectionCheck() {
ScheduledFuture<?> connectionCheckTask = this.connectionCheckTask;
if (connectionCheckTask != null) { if (connectionCheckTask != null) {
logger.debug("Stop periodic connection check"); logger.debug("Stop periodic connection check");
connectionCheckTask.cancel(true); connectionCheckTask.cancel(true);
connectionCheckTask = null; this.connectionCheckTask = null;
} }
} }
} }

View File

@ -22,13 +22,14 @@ import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.measure.quantity.Temperature; import javax.measure.quantity.Temperature;
import org.openhab.binding.melcloud.internal.api.json.DeviceStatus; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.melcloud.internal.api.dto.DeviceStatus;
import org.openhab.binding.melcloud.internal.config.AcDeviceConfig; import org.openhab.binding.melcloud.internal.config.AcDeviceConfig;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException;
@ -46,6 +47,7 @@ import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo; import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command; import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType; import org.openhab.core.types.RefreshType;
@ -59,7 +61,7 @@ import org.slf4j.LoggerFactory;
* @author Luca Calcaterra - Initial contribution * @author Luca Calcaterra - Initial contribution
* @author Pauli Anttila - Refactoring * @author Pauli Anttila - Refactoring
*/ */
@NonNullByDefault
public class MelCloudDeviceHandler extends BaseThingHandler { public class MelCloudDeviceHandler extends BaseThingHandler {
private static final int EFFECTIVE_FLAG_POWER = 0x01; private static final int EFFECTIVE_FLAG_POWER = 0x01;
@ -70,10 +72,10 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
private static final int EFFECTIVE_FLAG_VANE_HORIZONTAL = 0x100; private static final int EFFECTIVE_FLAG_VANE_HORIZONTAL = 0x100;
private final Logger logger = LoggerFactory.getLogger(MelCloudDeviceHandler.class); private final Logger logger = LoggerFactory.getLogger(MelCloudDeviceHandler.class);
private AcDeviceConfig config; private AcDeviceConfig config = new AcDeviceConfig();
private MelCloudAccountHandler melCloudHandler; private @Nullable MelCloudAccountHandler melCloudHandler;
private DeviceStatus deviceStatus; private @Nullable DeviceStatus deviceStatus;
private ScheduledFuture<?> refreshTask; private @Nullable ScheduledFuture<?> refreshTask;
public MelCloudDeviceHandler(Thing thing) { public MelCloudDeviceHandler(Thing thing) {
super(thing); super(thing);
@ -84,7 +86,7 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
logger.debug("Initializing {} handler.", getThing().getThingTypeUID()); logger.debug("Initializing {} handler.", getThing().getThingTypeUID());
Bridge bridge = getBridge(); Bridge bridge = getBridge();
if (bridge == null) { if (bridge == null || !(bridge.getHandler() instanceof BridgeHandler bridgeHandler)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge Not set"); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge Not set");
return; return;
} }
@ -92,15 +94,16 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
config = getConfigAs(AcDeviceConfig.class); config = getConfigAs(AcDeviceConfig.class);
logger.debug("A.C. device config: {}", config); logger.debug("A.C. device config: {}", config);
initializeBridge(bridge.getHandler(), bridge.getStatus()); initializeBridge(bridgeHandler, bridge.getStatus());
} }
@Override @Override
public void dispose() { public void dispose() {
logger.debug("Running dispose()"); logger.debug("Running dispose()");
ScheduledFuture<?> refreshTask = this.refreshTask;
if (refreshTask != null) { if (refreshTask != null) {
refreshTask.cancel(true); refreshTask.cancel(true);
refreshTask = null; this.refreshTask = null;
} }
melCloudHandler = null; melCloudHandler = null;
} }
@ -109,25 +112,21 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID()); logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
Bridge bridge = getBridge(); Bridge bridge = getBridge();
if (bridge != null) { if (bridge != null && bridge.getHandler() instanceof BridgeHandler bridgeHandler) {
initializeBridge(bridge.getHandler(), bridgeStatusInfo.getStatus()); initializeBridge(bridgeHandler, bridgeStatusInfo.getStatus());
} }
} }
private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) { private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) {
logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID()); logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID());
if (thingHandler != null && bridgeStatus != null) { melCloudHandler = (MelCloudAccountHandler) thingHandler;
melCloudHandler = (MelCloudAccountHandler) thingHandler;
if (bridgeStatus == ThingStatus.ONLINE) { if (bridgeStatus == ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE); updateStatus(ThingStatus.ONLINE);
startAutomaticRefresh(); startAutomaticRefresh();
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
} else { } else {
updateStatus(ThingStatus.OFFLINE); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
} }
} }
@ -139,12 +138,12 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
logger.debug("Refresh command not supported"); logger.debug("Refresh command not supported");
return; return;
} }
MelCloudAccountHandler melCloudHandler = this.melCloudHandler;
if (melCloudHandler == null) { if (melCloudHandler == null) {
logger.warn("No connection to MELCloud available, ignoring command"); logger.warn("No connection to MELCloud available, ignoring command");
return; return;
} }
DeviceStatus deviceStatus = this.deviceStatus;
if (deviceStatus == null) { if (deviceStatus == null) {
logger.info("No initial data available, bridge is probably offline. Ignoring command"); logger.info("No initial data available, bridge is probably offline. Ignoring command");
return; return;
@ -229,18 +228,19 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
} }
private void startAutomaticRefresh() { private void startAutomaticRefresh() {
ScheduledFuture<?> refreshTask = this.refreshTask;
if (refreshTask == null || refreshTask.isCancelled()) { if (refreshTask == null || refreshTask.isCancelled()) {
refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1, this.refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1,
config.pollingInterval, TimeUnit.SECONDS); config.pollingInterval, TimeUnit.SECONDS);
} }
} }
private void getDeviceDataAndUpdateChannels() { private void getDeviceDataAndUpdateChannels() {
if (melCloudHandler.isConnected()) { MelCloudAccountHandler melCloudHandler = this.melCloudHandler;
if (melCloudHandler != null && melCloudHandler.isConnected()) {
logger.debug("Update device '{}' channels", getThing().getThingTypeUID()); logger.debug("Update device '{}' channels", getThing().getThingTypeUID());
try { try {
DeviceStatus newDeviceStatus = melCloudHandler.fetchDeviceStatus(config.deviceID, DeviceStatus newDeviceStatus = melCloudHandler.fetchDeviceStatus(config.deviceID, config.buildingID);
Optional.ofNullable(config.buildingID));
updateChannels(newDeviceStatus); updateChannels(newDeviceStatus);
} catch (MelCloudLoginException e) { } catch (MelCloudLoginException e) {
logger.debug("Login error occurred during device '{}' polling, reason {}. ", logger.debug("Login error occurred during device '{}' polling, reason {}. ",
@ -255,7 +255,7 @@ public class MelCloudDeviceHandler extends BaseThingHandler {
} }
private synchronized void updateChannels(DeviceStatus newDeviceStatus) { private synchronized void updateChannels(DeviceStatus newDeviceStatus) {
deviceStatus = newDeviceStatus; DeviceStatus deviceStatus = this.deviceStatus = newDeviceStatus;
for (Channel channel : getThing().getChannels()) { for (Channel channel : getThing().getChannels()) {
updateChannels(channel.getUID().getId(), deviceStatus); updateChannels(channel.getUID().getId(), deviceStatus);
} }

View File

@ -22,13 +22,14 @@ import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.measure.quantity.Temperature; import javax.measure.quantity.Temperature;
import org.openhab.binding.melcloud.internal.api.json.HeatpumpDeviceStatus; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.melcloud.internal.api.dto.HeatpumpDeviceStatus;
import org.openhab.binding.melcloud.internal.config.HeatpumpDeviceConfig; import org.openhab.binding.melcloud.internal.config.HeatpumpDeviceConfig;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException;
import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException;
@ -45,6 +46,7 @@ import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo; import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command; import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType; import org.openhab.core.types.RefreshType;
@ -57,16 +59,17 @@ import org.slf4j.LoggerFactory;
* *
* @author Wietse van Buitenen - Initial contribution * @author Wietse van Buitenen - Initial contribution
*/ */
@NonNullByDefault
public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler { public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
private static final long EFFECTIVE_FLAG_POWER = 1L; private static final long EFFECTIVE_FLAG_POWER = 1L;
private static final long EFFECTIVE_FLAG_TEMPERATURE_ZONE1 = 8589934720L; private static final long EFFECTIVE_FLAG_TEMPERATURE_ZONE1 = 8589934720L;
private static final long EFFECTIVE_FLAG_HOTWATER = 65536L; private static final long EFFECTIVE_FLAG_HOTWATER = 65536L;
private final Logger logger = LoggerFactory.getLogger(MelCloudHeatpumpDeviceHandler.class); private final Logger logger = LoggerFactory.getLogger(MelCloudHeatpumpDeviceHandler.class);
private HeatpumpDeviceConfig config; private HeatpumpDeviceConfig config = new HeatpumpDeviceConfig();
private MelCloudAccountHandler melCloudHandler; private @Nullable MelCloudAccountHandler melCloudHandler;
private HeatpumpDeviceStatus heatpumpDeviceStatus; private @Nullable HeatpumpDeviceStatus heatpumpDeviceStatus;
private ScheduledFuture<?> refreshTask; private @Nullable ScheduledFuture<?> refreshTask;
public MelCloudHeatpumpDeviceHandler(Thing thing) { public MelCloudHeatpumpDeviceHandler(Thing thing) {
super(thing); super(thing);
@ -77,7 +80,7 @@ public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
logger.debug("Initializing {} handler.", getThing().getThingTypeUID()); logger.debug("Initializing {} handler.", getThing().getThingTypeUID());
Bridge bridge = getBridge(); Bridge bridge = getBridge();
if (bridge == null) { if (bridge == null || !(bridge.getHandler() instanceof BridgeHandler bridgeHandler)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge Not set"); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge Not set");
return; return;
} }
@ -85,15 +88,16 @@ public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
config = getConfigAs(HeatpumpDeviceConfig.class); config = getConfigAs(HeatpumpDeviceConfig.class);
logger.debug("Heatpump device config: {}", config); logger.debug("Heatpump device config: {}", config);
initializeBridge(bridge.getHandler(), bridge.getStatus()); initializeBridge(bridgeHandler, bridge.getStatus());
} }
@Override @Override
public void dispose() { public void dispose() {
logger.debug("Running dispose()"); logger.debug("Running dispose()");
ScheduledFuture<?> refreshTask = this.refreshTask;
if (refreshTask != null) { if (refreshTask != null) {
refreshTask.cancel(true); refreshTask.cancel(true);
refreshTask = null; this.refreshTask = null;
} }
melCloudHandler = null; melCloudHandler = null;
} }
@ -102,25 +106,21 @@ public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID()); logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
Bridge bridge = getBridge(); Bridge bridge = getBridge();
if (bridge != null) { if (bridge != null && bridge.getHandler() instanceof BridgeHandler bridgeHandler) {
initializeBridge(bridge.getHandler(), bridgeStatusInfo.getStatus()); initializeBridge(bridgeHandler, bridgeStatusInfo.getStatus());
} }
} }
private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) { private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) {
logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID()); logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID());
if (thingHandler != null && bridgeStatus != null) { melCloudHandler = (MelCloudAccountHandler) thingHandler;
melCloudHandler = (MelCloudAccountHandler) thingHandler;
if (bridgeStatus == ThingStatus.ONLINE) { if (bridgeStatus == ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE); updateStatus(ThingStatus.ONLINE);
startAutomaticRefresh(); startAutomaticRefresh();
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
} else { } else {
updateStatus(ThingStatus.OFFLINE); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
} }
} }
@ -133,11 +133,12 @@ public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
return; return;
} }
MelCloudAccountHandler melCloudHandler = this.melCloudHandler;
if (melCloudHandler == null) { if (melCloudHandler == null) {
logger.warn("No connection to MELCloud available, ignoring command"); logger.warn("No connection to MELCloud available, ignoring command");
return; return;
} }
HeatpumpDeviceStatus heatpumpDeviceStatus = this.heatpumpDeviceStatus;
if (heatpumpDeviceStatus == null) { if (heatpumpDeviceStatus == null) {
logger.info("No initial data available, bridge is probably offline. Ignoring command"); logger.info("No initial data available, bridge is probably offline. Ignoring command");
return; return;
@ -207,18 +208,20 @@ public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
} }
private void startAutomaticRefresh() { private void startAutomaticRefresh() {
ScheduledFuture<?> refreshTask = this.refreshTask;
if (refreshTask == null || refreshTask.isCancelled()) { if (refreshTask == null || refreshTask.isCancelled()) {
refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1, this.refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1,
config.pollingInterval, TimeUnit.SECONDS); config.pollingInterval, TimeUnit.SECONDS);
} }
} }
private void getDeviceDataAndUpdateChannels() { private void getDeviceDataAndUpdateChannels() {
if (melCloudHandler.isConnected()) { MelCloudAccountHandler melCloudHandler = this.melCloudHandler;
if (melCloudHandler != null && melCloudHandler.isConnected()) {
logger.debug("Update device '{}' channels", getThing().getThingTypeUID()); logger.debug("Update device '{}' channels", getThing().getThingTypeUID());
try { try {
HeatpumpDeviceStatus newHeatpumpDeviceStatus = melCloudHandler HeatpumpDeviceStatus newHeatpumpDeviceStatus = melCloudHandler
.fetchHeatpumpDeviceStatus(config.deviceID, Optional.ofNullable(config.buildingID)); .fetchHeatpumpDeviceStatus(config.deviceID, config.buildingID);
updateChannels(newHeatpumpDeviceStatus); updateChannels(newHeatpumpDeviceStatus);
} catch (MelCloudLoginException e) { } catch (MelCloudLoginException e) {
logger.debug("Login error occurred during device '{}' polling, reason {}. ", logger.debug("Login error occurred during device '{}' polling, reason {}. ",
@ -233,7 +236,7 @@ public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler {
} }
private synchronized void updateChannels(HeatpumpDeviceStatus newHeatpumpDeviceStatus) { private synchronized void updateChannels(HeatpumpDeviceStatus newHeatpumpDeviceStatus) {
heatpumpDeviceStatus = newHeatpumpDeviceStatus; HeatpumpDeviceStatus heatpumpDeviceStatus = this.heatpumpDeviceStatus = newHeatpumpDeviceStatus;
for (Channel channel : getThing().getChannels()) { for (Channel channel : getThing().getChannels()) {
updateChannels(channel.getUID().getId(), heatpumpDeviceStatus); updateChannels(channel.getUID().getId(), heatpumpDeviceStatus);
} }