From d2d2e6301678bb176835536472a5be3e46876714 Mon Sep 17 00:00:00 2001 From: lsiepel Date: Mon, 9 Sep 2024 21:21:37 +0200 Subject: [PATCH] [melcloud] Improve null handling (#17295) * Add null annotations Signed-off-by: Leo Siepel --- .../internal/MelCloudBindingConstants.java | 2 + .../internal/MelCloudHandlerFactory.java | 2 + .../internal/api/MelCloudConnection.java | 35 ++++++------ .../internal/api/{json => dto}/Area.java | 2 +- .../internal/api/{json => dto}/Device.java | 2 +- .../api/{json => dto}/DeviceProps.java | 2 +- .../api/{json => dto}/DeviceStatus.java | 2 +- .../internal/api/{json => dto}/Floor.java | 2 +- .../{json => dto}/HeatpumpDeviceStatus.java | 2 +- .../{json => dto}/ListDevicesResponse.java | 2 +- .../{json => dto}/LoginClientResponse.java | 2 +- .../internal/api/{json => dto}/LoginData.java | 2 +- .../internal/api/{json => dto}/Preset.java | 2 +- .../{json => dto}/QuantizedCoordinates.java | 2 +- .../internal/api/{json => dto}/Structure.java | 2 +- .../api/{json => dto}/WeatherObservation.java | 2 +- .../internal/config/AcDeviceConfig.java | 10 +++- .../internal/config/AccountConfig.java | 14 ++--- .../internal/config/HeatpumpDeviceConfig.java | 10 +++- .../discovery/MelCloudDiscoveryService.java | 20 ++++--- .../exceptions/MelCloudCommException.java | 3 + .../exceptions/MelCloudLoginException.java | 3 + .../handler/MelCloudAccountHandler.java | 48 ++++++++-------- .../handler/MelCloudDeviceHandler.java | 56 +++++++++---------- .../MelCloudHeatpumpDeviceHandler.java | 53 +++++++++--------- 25 files changed, 154 insertions(+), 128 deletions(-) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/Area.java (98%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/Device.java (99%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/DeviceProps.java (99%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/DeviceStatus.java (99%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/Floor.java (98%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/HeatpumpDeviceStatus.java (99%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/ListDevicesResponse.java (99%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/LoginClientResponse.java (98%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/LoginData.java (99%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/Preset.java (98%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/QuantizedCoordinates.java (95%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/Structure.java (96%) rename bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/{json => dto}/WeatherObservation.java (98%) diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudBindingConstants.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudBindingConstants.java index 6971de6aead60..a4b556adf0ee4 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudBindingConstants.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudBindingConstants.java @@ -17,6 +17,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; /** @@ -26,6 +27,7 @@ * @author Luca Calcaterra - Initial contribution * @author Wietse van Buitenen - Added heatpump device */ +@NonNullByDefault public class MelCloudBindingConstants { private static final String BINDING_ID = "melcloud"; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudHandlerFactory.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudHandlerFactory.java index 65f55993dc6d3..67fe1127a9487 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudHandlerFactory.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/MelCloudHandlerFactory.java @@ -14,6 +14,7 @@ import static org.openhab.binding.melcloud.internal.MelCloudBindingConstants.*; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.melcloud.internal.handler.MelCloudAccountHandler; import org.openhab.binding.melcloud.internal.handler.MelCloudDeviceHandler; @@ -33,6 +34,7 @@ * @author Luca Calcaterra - Initial contribution * @author Wietse van Buitenen - Added heatpump device */ +@NonNullByDefault @Component(configurationPid = "binding.melcloud", service = ThingHandlerFactory.class) public class MelCloudHandlerFactory extends BaseThingHandlerFactory { diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/MelCloudConnection.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/MelCloudConnection.java index 5733a26206eba..7343d1038feac 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/MelCloudConnection.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/MelCloudConnection.java @@ -19,13 +19,15 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Properties; -import org.openhab.binding.melcloud.internal.api.json.Device; -import org.openhab.binding.melcloud.internal.api.json.DeviceStatus; -import org.openhab.binding.melcloud.internal.api.json.HeatpumpDeviceStatus; -import org.openhab.binding.melcloud.internal.api.json.ListDevicesResponse; -import org.openhab.binding.melcloud.internal.api.json.LoginClientResponse; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.melcloud.internal.api.dto.Device; +import org.openhab.binding.melcloud.internal.api.dto.DeviceStatus; +import org.openhab.binding.melcloud.internal.api.dto.HeatpumpDeviceStatus; +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.MelCloudLoginException; import org.openhab.core.io.net.http.HttpUtil; @@ -45,6 +47,7 @@ * @author Pauli Anttila - Refactoring * @author Wietse van Buitenen - Return all devices, added heatpump device */ +@NonNullByDefault public class MelCloudConnection { 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; // 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(); private final Logger logger = LoggerFactory.getLogger(MelCloudConnection.class); private boolean isConnected = false; - private String sessionKey; + private String sessionKey = ""; public void login(String username, String password, int languageId) throws MelCloudCommException, MelCloudLoginException { setConnected(false); - sessionKey = null; + sessionKey = ""; JsonObject jsonReq = new JsonObject(); jsonReq.addProperty("Email", username); jsonReq.addProperty("Password", password); @@ -79,7 +82,7 @@ public void login(String username, String password, int languageId) String loginResponse = HttpUtil.executeUrl("POST", LOGIN_URL, null, data, "application/json", TIMEOUT_MILLISECONDS); 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) { String errorMsg = String.format("Login failed, error code: %s", resp.getErrorId()); if (resp.getErrorMessage() != null) { @@ -101,7 +104,7 @@ public List fetchDeviceList() throws MelCloudCommException { TIMEOUT_MILLISECONDS); logger.debug("Device list response: {}", response); List devices = new ArrayList<>(); - ListDevicesResponse[] buildings = gson.fromJson(response, ListDevicesResponse[].class); + ListDevicesResponse[] buildings = GSON.fromJson(response, ListDevicesResponse[].class); Arrays.asList(buildings).forEach(building -> { if (building.getStructure().getDevices() != null) { devices.addAll(building.getStructure().getDevices()); @@ -137,7 +140,7 @@ public DeviceStatus fetchDeviceStatus(int deviceId, int buildingId) throws MelCl try { String response = HttpUtil.executeUrl("GET", url, getHeaderProperties(), null, null, TIMEOUT_MILLISECONDS); logger.debug("Device status response: {}", response); - return gson.fromJson(response, DeviceStatus.class); + return Objects.requireNonNull(GSON.fromJson(response, DeviceStatus.class)); } catch (IOException | JsonSyntaxException e) { setConnected(false); throw new MelCloudCommException("Error occurred during device status fetch", e); @@ -146,14 +149,14 @@ public DeviceStatus fetchDeviceStatus(int deviceId, int buildingId) throws MelCl public DeviceStatus sendDeviceStatus(DeviceStatus deviceStatus) throws MelCloudCommException { assertConnected(); - String content = gson.toJson(deviceStatus, DeviceStatus.class); + String content = GSON.toJson(deviceStatus, DeviceStatus.class); logger.debug("Sending device status: {}", content); InputStream data = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); try { String response = HttpUtil.executeUrl("POST", DEVICE_URL + "/SetAta", getHeaderProperties(), data, "application/json", TIMEOUT_MILLISECONDS); 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) { setConnected(false); throw new MelCloudCommException("Error occurred during device command sending", e); @@ -166,7 +169,7 @@ public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, int building try { String response = HttpUtil.executeUrl("GET", url, getHeaderProperties(), null, null, TIMEOUT_MILLISECONDS); 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) { setConnected(false); throw new MelCloudCommException("Error occurred during heatpump device status fetch", e); @@ -176,14 +179,14 @@ public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, int building public HeatpumpDeviceStatus sendHeatpumpDeviceStatus(HeatpumpDeviceStatus heatpumpDeviceStatus) throws MelCloudCommException { assertConnected(); - String content = gson.toJson(heatpumpDeviceStatus, HeatpumpDeviceStatus.class); + String content = GSON.toJson(heatpumpDeviceStatus, HeatpumpDeviceStatus.class); logger.debug("Sending heatpump device status: {}", content); InputStream data = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); try { String response = HttpUtil.executeUrl("POST", DEVICE_URL + "/SetAtw", getHeaderProperties(), data, "application/json", TIMEOUT_MILLISECONDS); 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) { setConnected(false); throw new MelCloudCommException("Error occurred during heatpump device command sending", e); diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Area.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Area.java similarity index 98% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Area.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Area.java index 8fe80863817f5..8167b039c5d6b 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Area.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Area.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Device.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Device.java similarity index 99% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Device.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Device.java index 45e2253aa4b60..2c28b379ebfe9 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Device.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Device.java @@ -10,7 +10,7 @@ * * 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.util.List; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/DeviceProps.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/DeviceProps.java similarity index 99% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/DeviceProps.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/DeviceProps.java index 82d15fddfb3bc..375fbcd029387 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/DeviceProps.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/DeviceProps.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/DeviceStatus.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/DeviceStatus.java similarity index 99% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/DeviceStatus.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/DeviceStatus.java index a658b4eddb5c8..d6782fa431170 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/DeviceStatus.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/DeviceStatus.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Floor.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Floor.java similarity index 98% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Floor.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Floor.java index 2abc707720d57..df39ddc2a9701 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Floor.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Floor.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/HeatpumpDeviceStatus.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/HeatpumpDeviceStatus.java similarity index 99% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/HeatpumpDeviceStatus.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/HeatpumpDeviceStatus.java index edfaee58e0e67..b80b943adcd80 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/HeatpumpDeviceStatus.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/HeatpumpDeviceStatus.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/ListDevicesResponse.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/ListDevicesResponse.java similarity index 99% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/ListDevicesResponse.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/ListDevicesResponse.java index 1ff74bf2ade74..cfe739ed70692 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/ListDevicesResponse.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/ListDevicesResponse.java @@ -10,7 +10,7 @@ * * 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.SerializedName; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/LoginClientResponse.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/LoginClientResponse.java similarity index 98% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/LoginClientResponse.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/LoginClientResponse.java index c9e0ac06473aa..54f94626a0bb2 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/LoginClientResponse.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/LoginClientResponse.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/LoginData.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/LoginData.java similarity index 99% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/LoginData.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/LoginData.java index 5c766be09f8ec..e09b1d0aea6cb 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/LoginData.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/LoginData.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Preset.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Preset.java similarity index 98% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Preset.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Preset.java index 612887203e11a..5570cd16f9864 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Preset.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Preset.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/QuantizedCoordinates.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/QuantizedCoordinates.java similarity index 95% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/QuantizedCoordinates.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/QuantizedCoordinates.java index c3b1ca3075114..34490b13b4581 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/QuantizedCoordinates.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/QuantizedCoordinates.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Structure.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Structure.java similarity index 96% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Structure.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Structure.java index b48cafec53773..840a059812203 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/Structure.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/Structure.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/WeatherObservation.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/WeatherObservation.java similarity index 98% rename from bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/WeatherObservation.java rename to bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/WeatherObservation.java index 4e167226e68e5..ed16b1147da04 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/json/WeatherObservation.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/api/dto/WeatherObservation.java @@ -10,7 +10,7 @@ * * 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; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AcDeviceConfig.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AcDeviceConfig.java index d48592d907e1e..b568913376d51 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AcDeviceConfig.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AcDeviceConfig.java @@ -12,17 +12,21 @@ */ 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. * * @author Pauli Anttila - Initial Contribution * */ +@NonNullByDefault public class AcDeviceConfig { - public Integer deviceID; - public Integer buildingID; - public Integer pollingInterval; + public Integer deviceID = 0; + public @Nullable Integer buildingID; + public Integer pollingInterval = 360; @Override public String toString() { diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AccountConfig.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AccountConfig.java index e6f41dd5bd0c5..cbb5081d42c4c 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AccountConfig.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/AccountConfig.java @@ -12,17 +12,20 @@ */ package org.openhab.binding.melcloud.internal.config; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Config class for MELCloud account parameters. * * @author Pauli Anttila - Initial Contribution * */ +@NonNullByDefault public class AccountConfig { - public String username; - public String password; - public int language; + public String username = ""; + public String password = ""; + public int language = 0; @Override public String toString() { @@ -30,9 +33,6 @@ public String toString() { } private String getPasswordForPrinting() { - if (password != null) { - return password.isEmpty() ? "" : "*********"; - } - return ""; + return password.isEmpty() ? "" : "*********"; } } diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/HeatpumpDeviceConfig.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/HeatpumpDeviceConfig.java index 6fdd0eea0498a..f3abda22cafc2 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/HeatpumpDeviceConfig.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/config/HeatpumpDeviceConfig.java @@ -12,16 +12,20 @@ */ 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. * * @author Wietse van Buitenen - Initial Contribution * */ +@NonNullByDefault public class HeatpumpDeviceConfig { - public Integer deviceID; - public Integer buildingID; - public Integer pollingInterval; + public Integer deviceID = 0; + public @Nullable Integer buildingID; + public Integer pollingInterval = 360; @Override public String toString() { diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/discovery/MelCloudDiscoveryService.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/discovery/MelCloudDiscoveryService.java index 9134d8482e7b9..76e2b51c3ef05 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/discovery/MelCloudDiscoveryService.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/discovery/MelCloudDiscoveryService.java @@ -20,9 +20,10 @@ import java.util.concurrent.ScheduledFuture; 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.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.MelCloudLoginException; import org.openhab.binding.melcloud.internal.handler.MelCloudAccountHandler; @@ -43,14 +44,15 @@ * @author Pauli Anttila - Refactoring * @author Wietse van Buitenen - Check device type, added heatpump device */ +@NonNullByDefault @Component(scope = ServiceScope.PROTOTYPE, service = MelCloudDiscoveryService.class) -public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryService<@NonNull MelCloudAccountHandler> { +public class MelCloudDiscoveryService extends AbstractThingHandlerDiscoveryService { private final Logger logger = LoggerFactory.getLogger(MelCloudDiscoveryService.class); private static final String PROPERTY_DEVICE_ID = "deviceID"; private static final int DISCOVER_TIMEOUT_SECONDS = 10; - private ScheduledFuture scanTask; + private @Nullable ScheduledFuture scanTask; /** * Creates a MelCloudDiscoveryService with enabled autostart. @@ -67,7 +69,8 @@ protected void startBackgroundDiscovery() { @Override protected void startScan() { - if (this.scanTask != null) { + ScheduledFuture scanTask = this.scanTask; + if (scanTask != null) { scanTask.cancel(true); } this.scanTask = scheduler.schedule(() -> discoverDevices(), 0, TimeUnit.SECONDS); @@ -77,8 +80,9 @@ protected void startScan() { protected void stopScan() { super.stopScan(); - if (this.scanTask != null) { - this.scanTask.cancel(true); + ScheduledFuture scanTask = this.scanTask; + if (scanTask != null) { + scanTask.cancel(true); this.scanTask = null; } } @@ -88,7 +92,7 @@ private void discoverDevices() { try { List deviceList = thingHandler.getDeviceList(); - if (deviceList == null) { + if (deviceList.isEmpty()) { logger.debug("No devices found"); } else { ThingUID bridgeUID = thingHandler.getThing().getUID(); diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudCommException.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudCommException.java index d9a03628a26b2..eb58b173c5838 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudCommException.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudCommException.java @@ -12,11 +12,14 @@ */ package org.openhab.binding.melcloud.internal.exceptions; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Exception to encapsulate any issues communicating with MELCloud. * * @author Pauli Anttila - Initial Contribution */ +@NonNullByDefault public class MelCloudCommException extends Exception { private static final long serialVersionUID = 1L; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudLoginException.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudLoginException.java index 7f8cf58941d04..4a58af4646311 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudLoginException.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/exceptions/MelCloudLoginException.java @@ -12,11 +12,14 @@ */ package org.openhab.binding.melcloud.internal.exceptions; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Exception to encapsulate any login issues with MELCloud. * * @author Pauli Anttila - Initial Contribution */ +@NonNullByDefault public class MelCloudLoginException extends Exception { private static final long serialVersionUID = 1L; diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudAccountHandler.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudAccountHandler.java index 1414b2322e370..33f3859f65b27 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudAccountHandler.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudAccountHandler.java @@ -15,15 +15,16 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.concurrent.ScheduledFuture; 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.json.Device; -import org.openhab.binding.melcloud.internal.api.json.DeviceStatus; -import org.openhab.binding.melcloud.internal.api.json.HeatpumpDeviceStatus; +import org.openhab.binding.melcloud.internal.api.dto.Device; +import org.openhab.binding.melcloud.internal.api.dto.DeviceStatus; +import org.openhab.binding.melcloud.internal.api.dto.HeatpumpDeviceStatus; import org.openhab.binding.melcloud.internal.config.AccountConfig; import org.openhab.binding.melcloud.internal.discovery.MelCloudDiscoveryService; import org.openhab.binding.melcloud.internal.exceptions.MelCloudCommException; @@ -47,14 +48,15 @@ * @author Pauli Anttila - Refactoring * @author Wietse van Buitenen - Return all devices, added heatpump device */ +@NonNullByDefault public class MelCloudAccountHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(MelCloudAccountHandler.class); - private MelCloudConnection connection; - private List devices; - private ScheduledFuture connectionCheckTask; - private AccountConfig config; - private boolean loginCredentialError; + private MelCloudConnection connection = new MelCloudConnection(); + private List devices = Collections.emptyList(); + private @Nullable ScheduledFuture connectionCheckTask; + private AccountConfig config = new AccountConfig(); + private boolean loginCredentialError = false; public MelCloudAccountHandler(Bridge bridge) { super(bridge); @@ -69,8 +71,6 @@ public Collection> getServices() { public void initialize() { logger.debug("Initializing MELCloud account handler."); config = getConfigAs(AccountConfig.class); - connection = new MelCloudConnection(); - devices = Collections.emptyList(); loginCredentialError = false; startConnectionCheck(); } @@ -79,9 +79,7 @@ public void initialize() { public void dispose() { logger.debug("Running dispose()"); stopConnectionCheck(); - connection = null; devices = Collections.emptyList(); - config = null; } @Override @@ -102,6 +100,7 @@ private void connect() throws MelCloudCommException, MelCloudLoginException { throw new MelCloudLoginException("Connection to MELCloud can't be opened because of wrong credentials"); } logger.debug("Initializing connection to MELCloud"); + updateStatus(ThingStatus.OFFLINE); try { connection.login(config.username, config.password, config.language); @@ -139,10 +138,10 @@ public DeviceStatus sendDeviceStatus(DeviceStatus deviceStatus) } } - public DeviceStatus fetchDeviceStatus(int deviceId, Optional buildingId) + public DeviceStatus fetchDeviceStatus(int deviceId, @Nullable Integer buildingId) throws MelCloudCommException, MelCloudLoginException { connectIfNotConnected(); - int bid = buildingId.orElse(findBuildingId(deviceId)); + int bid = buildingId != null ? buildingId : findBuildingId(deviceId); try { return connection.fetchDeviceStatus(deviceId, bid); @@ -165,10 +164,10 @@ public HeatpumpDeviceStatus sendHeatpumpDeviceStatus(HeatpumpDeviceStatus heatpu } } - public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, Optional buildingId) + public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, @Nullable Integer buildingId) throws MelCloudCommException, MelCloudLoginException { connectIfNotConnected(); - int bid = buildingId.orElse(findBuildingId(deviceId)); + int bid = buildingId != null ? buildingId : findBuildingId(deviceId); try { return connection.fetchHeatpumpDeviceStatus(deviceId, bid); @@ -180,15 +179,13 @@ public HeatpumpDeviceStatus fetchHeatpumpDeviceStatus(int deviceId, Optional d.getDeviceID() == deviceId).findFirst().orElseThrow( - () -> new MelCloudCommException(String.format("Can't find building id for device id %s", deviceId))) - .getBuildingID(); - } - throw new MelCloudCommException(String.format("Can't find building id for device id %s", deviceId)); + return devices.stream().filter(d -> d.getDeviceID() == deviceId).findFirst().orElseThrow( + () -> new MelCloudCommException(String.format("Can't find building id for device id %s", deviceId))) + .getBuildingID(); } private void startConnectionCheck() { + ScheduledFuture connectionCheckTask = this.connectionCheckTask; if (connectionCheckTask == null || connectionCheckTask.isCancelled()) { logger.debug("Start periodic connection check"); Runnable runnable = () -> { @@ -207,17 +204,18 @@ private void startConnectionCheck() { } } }; - connectionCheckTask = scheduler.scheduleWithFixedDelay(runnable, 0, 300, TimeUnit.SECONDS); + this.connectionCheckTask = scheduler.scheduleWithFixedDelay(runnable, 0, 300, TimeUnit.SECONDS); } else { logger.debug("Connection check task already running"); } } private void stopConnectionCheck() { + ScheduledFuture connectionCheckTask = this.connectionCheckTask; if (connectionCheckTask != null) { logger.debug("Stop periodic connection check"); connectionCheckTask.cancel(true); - connectionCheckTask = null; + this.connectionCheckTask = null; } } } diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudDeviceHandler.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudDeviceHandler.java index 0448b8c46c943..6a43e759f8fb5 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudDeviceHandler.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudDeviceHandler.java @@ -22,13 +22,14 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Optional; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; 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.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException; @@ -46,6 +47,7 @@ import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingStatusInfo; 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.types.Command; import org.openhab.core.types.RefreshType; @@ -59,7 +61,7 @@ * @author Luca Calcaterra - Initial contribution * @author Pauli Anttila - Refactoring */ - +@NonNullByDefault public class MelCloudDeviceHandler extends BaseThingHandler { 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 final Logger logger = LoggerFactory.getLogger(MelCloudDeviceHandler.class); - private AcDeviceConfig config; - private MelCloudAccountHandler melCloudHandler; - private DeviceStatus deviceStatus; - private ScheduledFuture refreshTask; + private AcDeviceConfig config = new AcDeviceConfig(); + private @Nullable MelCloudAccountHandler melCloudHandler; + private @Nullable DeviceStatus deviceStatus; + private @Nullable ScheduledFuture refreshTask; public MelCloudDeviceHandler(Thing thing) { super(thing); @@ -84,7 +86,7 @@ public void initialize() { logger.debug("Initializing {} handler.", getThing().getThingTypeUID()); Bridge bridge = getBridge(); - if (bridge == null) { + if (bridge == null || !(bridge.getHandler() instanceof BridgeHandler bridgeHandler)) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge Not set"); return; } @@ -92,15 +94,16 @@ public void initialize() { config = getConfigAs(AcDeviceConfig.class); logger.debug("A.C. device config: {}", config); - initializeBridge(bridge.getHandler(), bridge.getStatus()); + initializeBridge(bridgeHandler, bridge.getStatus()); } @Override public void dispose() { logger.debug("Running dispose()"); + ScheduledFuture refreshTask = this.refreshTask; if (refreshTask != null) { refreshTask.cancel(true); - refreshTask = null; + this.refreshTask = null; } melCloudHandler = null; } @@ -109,25 +112,21 @@ public void dispose() { public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID()); Bridge bridge = getBridge(); - if (bridge != null) { - initializeBridge(bridge.getHandler(), bridgeStatusInfo.getStatus()); + if (bridge != null && bridge.getHandler() instanceof BridgeHandler bridgeHandler) { + initializeBridge(bridgeHandler, bridgeStatusInfo.getStatus()); } } private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) { logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID()); - if (thingHandler != null && bridgeStatus != null) { - melCloudHandler = (MelCloudAccountHandler) thingHandler; + melCloudHandler = (MelCloudAccountHandler) thingHandler; - if (bridgeStatus == ThingStatus.ONLINE) { - updateStatus(ThingStatus.ONLINE); - startAutomaticRefresh(); - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); - } + if (bridgeStatus == ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + startAutomaticRefresh(); } else { - updateStatus(ThingStatus.OFFLINE); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); } } @@ -139,12 +138,12 @@ public void handleCommand(ChannelUID channelUID, Command command) { logger.debug("Refresh command not supported"); return; } - + MelCloudAccountHandler melCloudHandler = this.melCloudHandler; if (melCloudHandler == null) { logger.warn("No connection to MELCloud available, ignoring command"); return; } - + DeviceStatus deviceStatus = this.deviceStatus; if (deviceStatus == null) { logger.info("No initial data available, bridge is probably offline. Ignoring command"); return; @@ -229,18 +228,19 @@ private DeviceStatus getDeviceStatusCopy(DeviceStatus deviceStatus) { } private void startAutomaticRefresh() { + ScheduledFuture refreshTask = this.refreshTask; if (refreshTask == null || refreshTask.isCancelled()) { - refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1, + this.refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1, config.pollingInterval, TimeUnit.SECONDS); } } private void getDeviceDataAndUpdateChannels() { - if (melCloudHandler.isConnected()) { + MelCloudAccountHandler melCloudHandler = this.melCloudHandler; + if (melCloudHandler != null && melCloudHandler.isConnected()) { logger.debug("Update device '{}' channels", getThing().getThingTypeUID()); try { - DeviceStatus newDeviceStatus = melCloudHandler.fetchDeviceStatus(config.deviceID, - Optional.ofNullable(config.buildingID)); + DeviceStatus newDeviceStatus = melCloudHandler.fetchDeviceStatus(config.deviceID, config.buildingID); updateChannels(newDeviceStatus); } catch (MelCloudLoginException e) { logger.debug("Login error occurred during device '{}' polling, reason {}. ", @@ -255,7 +255,7 @@ private void getDeviceDataAndUpdateChannels() { } private synchronized void updateChannels(DeviceStatus newDeviceStatus) { - deviceStatus = newDeviceStatus; + DeviceStatus deviceStatus = this.deviceStatus = newDeviceStatus; for (Channel channel : getThing().getChannels()) { updateChannels(channel.getUID().getId(), deviceStatus); } diff --git a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudHeatpumpDeviceHandler.java b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudHeatpumpDeviceHandler.java index 276679a8a3d83..c34cfb2536d47 100644 --- a/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudHeatpumpDeviceHandler.java +++ b/bundles/org.openhab.binding.melcloud/src/main/java/org/openhab/binding/melcloud/internal/handler/MelCloudHeatpumpDeviceHandler.java @@ -22,13 +22,14 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Optional; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; 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.exceptions.MelCloudCommException; import org.openhab.binding.melcloud.internal.exceptions.MelCloudLoginException; @@ -45,6 +46,7 @@ import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingStatusInfo; 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.types.Command; import org.openhab.core.types.RefreshType; @@ -57,16 +59,17 @@ * * @author Wietse van Buitenen - Initial contribution */ +@NonNullByDefault public class MelCloudHeatpumpDeviceHandler extends BaseThingHandler { private static final long EFFECTIVE_FLAG_POWER = 1L; private static final long EFFECTIVE_FLAG_TEMPERATURE_ZONE1 = 8589934720L; private static final long EFFECTIVE_FLAG_HOTWATER = 65536L; private final Logger logger = LoggerFactory.getLogger(MelCloudHeatpumpDeviceHandler.class); - private HeatpumpDeviceConfig config; - private MelCloudAccountHandler melCloudHandler; - private HeatpumpDeviceStatus heatpumpDeviceStatus; - private ScheduledFuture refreshTask; + private HeatpumpDeviceConfig config = new HeatpumpDeviceConfig(); + private @Nullable MelCloudAccountHandler melCloudHandler; + private @Nullable HeatpumpDeviceStatus heatpumpDeviceStatus; + private @Nullable ScheduledFuture refreshTask; public MelCloudHeatpumpDeviceHandler(Thing thing) { super(thing); @@ -77,7 +80,7 @@ public void initialize() { logger.debug("Initializing {} handler.", getThing().getThingTypeUID()); Bridge bridge = getBridge(); - if (bridge == null) { + if (bridge == null || !(bridge.getHandler() instanceof BridgeHandler bridgeHandler)) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge Not set"); return; } @@ -85,15 +88,16 @@ public void initialize() { config = getConfigAs(HeatpumpDeviceConfig.class); logger.debug("Heatpump device config: {}", config); - initializeBridge(bridge.getHandler(), bridge.getStatus()); + initializeBridge(bridgeHandler, bridge.getStatus()); } @Override public void dispose() { logger.debug("Running dispose()"); + ScheduledFuture refreshTask = this.refreshTask; if (refreshTask != null) { refreshTask.cancel(true); - refreshTask = null; + this.refreshTask = null; } melCloudHandler = null; } @@ -102,25 +106,21 @@ public void dispose() { public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID()); Bridge bridge = getBridge(); - if (bridge != null) { - initializeBridge(bridge.getHandler(), bridgeStatusInfo.getStatus()); + if (bridge != null && bridge.getHandler() instanceof BridgeHandler bridgeHandler) { + initializeBridge(bridgeHandler, bridgeStatusInfo.getStatus()); } } private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) { logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID()); - if (thingHandler != null && bridgeStatus != null) { - melCloudHandler = (MelCloudAccountHandler) thingHandler; + melCloudHandler = (MelCloudAccountHandler) thingHandler; - if (bridgeStatus == ThingStatus.ONLINE) { - updateStatus(ThingStatus.ONLINE); - startAutomaticRefresh(); - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); - } + if (bridgeStatus == ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + startAutomaticRefresh(); } else { - updateStatus(ThingStatus.OFFLINE); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); } } @@ -133,11 +133,12 @@ public void handleCommand(ChannelUID channelUID, Command command) { return; } + MelCloudAccountHandler melCloudHandler = this.melCloudHandler; if (melCloudHandler == null) { logger.warn("No connection to MELCloud available, ignoring command"); return; } - + HeatpumpDeviceStatus heatpumpDeviceStatus = this.heatpumpDeviceStatus; if (heatpumpDeviceStatus == null) { logger.info("No initial data available, bridge is probably offline. Ignoring command"); return; @@ -207,18 +208,20 @@ private HeatpumpDeviceStatus getHeatpumpDeviceStatusCopy(HeatpumpDeviceStatus he } private void startAutomaticRefresh() { + ScheduledFuture refreshTask = this.refreshTask; if (refreshTask == null || refreshTask.isCancelled()) { - refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1, + this.refreshTask = scheduler.scheduleWithFixedDelay(this::getDeviceDataAndUpdateChannels, 1, config.pollingInterval, TimeUnit.SECONDS); } } private void getDeviceDataAndUpdateChannels() { - if (melCloudHandler.isConnected()) { + MelCloudAccountHandler melCloudHandler = this.melCloudHandler; + if (melCloudHandler != null && melCloudHandler.isConnected()) { logger.debug("Update device '{}' channels", getThing().getThingTypeUID()); try { HeatpumpDeviceStatus newHeatpumpDeviceStatus = melCloudHandler - .fetchHeatpumpDeviceStatus(config.deviceID, Optional.ofNullable(config.buildingID)); + .fetchHeatpumpDeviceStatus(config.deviceID, config.buildingID); updateChannels(newHeatpumpDeviceStatus); } catch (MelCloudLoginException e) { logger.debug("Login error occurred during device '{}' polling, reason {}. ", @@ -233,7 +236,7 @@ private void getDeviceDataAndUpdateChannels() { } private synchronized void updateChannels(HeatpumpDeviceStatus newHeatpumpDeviceStatus) { - heatpumpDeviceStatus = newHeatpumpDeviceStatus; + HeatpumpDeviceStatus heatpumpDeviceStatus = this.heatpumpDeviceStatus = newHeatpumpDeviceStatus; for (Channel channel : getThing().getChannels()) { updateChannels(channel.getUID().getId(), heatpumpDeviceStatus); }