From 1bae183f909201eed79014f49523336e2f409511 Mon Sep 17 00:00:00 2001 From: Laurent Garnier Date: Thu, 2 Jul 2020 00:30:01 +0200 Subject: [PATCH] [netatmo] Null annotations Part 3 of 3 Fix #7913 Signed-off-by: Laurent Garnier --- bundles/org.openhab.binding.netatmo/README.md | 12 +- .../internal/camera/CameraAddress.java | 15 +- .../internal/camera/CameraHandler.java | 39 ++-- .../NetatmoModuleDiscoveryService.java | 32 ++- .../handler/AbstractNetatmoThingHandler.java | 81 ++++--- .../handler/NetatmoBridgeHandler.java | 71 +++---- .../handler/NetatmoDeviceHandler.java | 78 +++---- .../handler/NetatmoModuleHandler.java | 60 +++--- .../homecoach/NAHealthyHomeCoachHandler.java | 32 +-- .../presence/NAPresenceCameraHandler.java | 28 +-- .../internal/station/NAMainHandler.java | 137 +++++------- .../internal/station/NAModule1Handler.java | 73 +++---- .../internal/station/NAModule2Handler.java | 37 ++-- .../internal/station/NAModule3Handler.java | 25 +-- .../internal/station/NAModule4Handler.java | 77 ++++--- .../internal/thermostat/NAPlugHandler.java | 53 ++--- .../internal/thermostat/NATherm1Handler.java | 136 ++++++------ .../welcome/NAWelcomeCameraHandler.java | 8 +- .../welcome/NAWelcomeHomeHandler.java | 121 ++++++----- .../welcome/NAWelcomePersonHandler.java | 82 ++++---- .../presence/NAPresenceCameraHandlerTest.java | 199 ++++++++++-------- .../welcome/NAWelcomeHomeHandlerTest.java | 100 +++++---- 22 files changed, 733 insertions(+), 763 deletions(-) diff --git a/bundles/org.openhab.binding.netatmo/README.md b/bundles/org.openhab.binding.netatmo/README.md index 0bc2b43e47bc0..57b0d4e55a079 100644 --- a/bundles/org.openhab.binding.netatmo/README.md +++ b/bundles/org.openhab.binding.netatmo/README.md @@ -503,10 +503,9 @@ All these channels are read only. ### Welcome and Presence Camera Warnings: -- The URL of the live snapshot is a fixed URL so the value of the channel cameraLivePictureUrl / welcomeCameraLivePictureUrl will never be updated once first set by the binding. -So to get a refreshed picture, you need to use the refresh parameter in your sitemap image element. -- Some features like the video surveillance are accessed via the local network, so it may be helpful to set a static IP address -for the camera within your local network. + +- The URL of the live snapshot is a fixed URL so the value of the channel cameraLivePictureUrl / welcomeCameraLivePictureUrl will never be updated once first set by the binding. So to get a refreshed picture, you need to use the refresh parameter in your sitemap image element. +- Some features like the video surveillance are accessed via the local network, so it may be helpful to set a static IP address for the camera within your local network. **Supported channels for the Welcome Camera thing:** @@ -523,9 +522,8 @@ for the camera within your local network. **Supported channels for the Presence Camera thing:** Warnings: -- The floodlight auto-mode (cameraFloodlightAutoMode) isn't updated it is changed by another application. Therefore the -binding handles its own state of the auto-mode. This has the advantage that the user can define its own floodlight -switch off behaviour. + +- The floodlight auto-mode (cameraFloodlightAutoMode) isn't updated it is changed by another application. Therefore the binding handles its own state of the auto-mode. This has the advantage that the user can define its own floodlight switch off behaviour. | Channel ID | Item Type | Read/Write | Description | |-----------------------------|-----------|------------|--------------------------------------------------------------| diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraAddress.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraAddress.java index af54e36fa5e7a..f5b17c52ae92c 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraAddress.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraAddress.java @@ -12,15 +12,15 @@ */ package org.openhab.binding.netatmo.internal.camera; +import java.util.Objects; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import java.util.Objects; - /** * {@link CameraAddress} handles the data to address a camera (VPN and local address). * - * @author Sven Strohschein + * @author Sven Strohschein - Initial contribution */ @NonNullByDefault public class CameraAddress { @@ -43,6 +43,7 @@ public String getLocalURL() { /** * Checks if the VPN URL was changed / isn't equal to the given VPN-URL. + * * @param vpnURL old / known VPN URL * @return true, when the VPN URL isn't equal given VPN URL, otherwise false */ @@ -52,8 +53,12 @@ public boolean isVpnURLChanged(String vpnURL) { @Override public boolean equals(@Nullable Object object) { - if (this == object) return true; - if (object == null || getClass() != object.getClass()) return false; + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } CameraAddress that = (CameraAddress) object; return vpnURL.equals(that.vpnURL) && localURL.equals(that.localURL); } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraHandler.java index 7d152ee466dde..8c92af03a3ad0 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraHandler.java @@ -12,11 +12,14 @@ */ package org.openhab.binding.netatmo.internal.camera; -import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*; +import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.toOnOffType; import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; -import org.eclipse.jdt.annotation.NonNull; +import java.io.IOException; +import java.util.Optional; + import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.thing.ChannelUID; @@ -29,19 +32,16 @@ import org.json.JSONObject; import org.openhab.binding.netatmo.internal.ChannelTypeUtils; import org.openhab.binding.netatmo.internal.handler.NetatmoModuleHandler; - -import io.swagger.client.model.NAWelcomeCamera; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.Optional; +import io.swagger.client.model.NAWelcomeCamera; /** * {@link CameraHandler} is the class used to handle Camera Data * - * @author Sven Strohschein (partly moved code from NAWelcomeCameraHandler to introduce inheritance, see - * NAWelcomeCameraHandler) + * @author Sven Strohschein - Initial contribution (partly moved code from NAWelcomeCameraHandler to introduce + * inheritance, see NAWelcomeCameraHandler) * */ @NonNullByDefault @@ -53,7 +53,7 @@ public abstract class CameraHandler extends NetatmoModuleHandler cameraAddress = Optional.empty(); + private @Nullable CameraAddress cameraAddress; protected CameraHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { super(thing, timeZoneProvider); @@ -65,9 +65,9 @@ public void handleCommand(ChannelUID channelUID, Command command) { switch (channelId) { case CHANNEL_CAMERA_STATUS: case CHANNEL_WELCOME_CAMERA_STATUS: - if(command == OnOffType.ON) { + if (command == OnOffType.ON) { switchVideoSurveillance(true); - } else if(command == OnOffType.OFF) { + } else if (command == OnOffType.OFF) { switchVideoSurveillance(false); } break; @@ -81,7 +81,7 @@ protected void updateProperties(NAWelcomeCamera moduleData) { } @Override - protected State getNAThingProperty(@NonNull String channelId) { + protected State getNAThingProperty(String channelId) { switch (channelId) { case CHANNEL_CAMERA_STATUS: return getStatusState(); @@ -188,7 +188,7 @@ private void switchVideoSurveillance(boolean isOn) { Optional localCameraURL = getLocalCameraURL(); if (localCameraURL.isPresent()) { String url = localCameraURL.get() + STATUS_CHANGE_URL_PATH + "?status="; - if(isOn) { + if (isOn) { url += "on"; } else { url += "off"; @@ -201,17 +201,20 @@ private void switchVideoSurveillance(boolean isOn) { protected Optional getLocalCameraURL() { Optional vpnURLOptional = getVpnUrl(); + CameraAddress address = cameraAddress; if (vpnURLOptional.isPresent()) { final String vpnURL = vpnURLOptional.get(); - //The local address is (re-)requested when it wasn't already determined or when the vpn address was changed. - if (!cameraAddress.isPresent() || cameraAddress.get().isVpnURLChanged(vpnURL)) { + // The local address is (re-)requested when it wasn't already determined or when the vpn address was + // changed. + if (address == null || address.isVpnURLChanged(vpnURL)) { Optional json = executeGETRequestJSON(vpnURL + PING_URL_PATH); - cameraAddress = json.map(j -> j.optString("local_url", null)) - .map(localURL -> new CameraAddress(vpnURL, localURL)); + address = json.map(j -> j.optString("local_url", null)) + .map(localURL -> new CameraAddress(vpnURL, localURL)).orElse(null); + cameraAddress = address; } } - return cameraAddress.map(CameraAddress::getLocalURL); + return Optional.ofNullable(address).map(CameraAddress::getLocalURL); } private Optional executeGETRequestJSON(String url) { diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/discovery/NetatmoModuleDiscoveryService.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/discovery/NetatmoModuleDiscoveryService.java index 46fc8bcdd6ebf..b8e508b451cda 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/discovery/NetatmoModuleDiscoveryService.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/discovery/NetatmoModuleDiscoveryService.java @@ -29,13 +29,9 @@ import org.openhab.binding.netatmo.internal.handler.NetatmoDataListener; import io.swagger.client.model.NAHealthyHomeCoach; -import io.swagger.client.model.NAHealthyHomeCoachDataBody; import io.swagger.client.model.NAMain; import io.swagger.client.model.NAPlug; -import io.swagger.client.model.NAStationDataBody; -import io.swagger.client.model.NAThermostatDataBody; import io.swagger.client.model.NAWelcomeHome; -import io.swagger.client.model.NAWelcomeHomeData; /** * The {@link NetatmoModuleDiscoveryService} searches for available Netatmo @@ -70,36 +66,32 @@ public void deactivate() { @Override public void startScan() { if (netatmoBridgeHandler.configuration.readStation) { - NAStationDataBody stationDataBody = netatmoBridgeHandler.getStationsDataBody(null); - if (stationDataBody != null) { - stationDataBody.getDevices().forEach(station -> { + netatmoBridgeHandler.getStationsDataBody(null).ifPresent(dataBody -> { + dataBody.getDevices().forEach(station -> { discoverWeatherStation(station); }); - } + }); } if (netatmoBridgeHandler.configuration.readHealthyHomeCoach) { - NAHealthyHomeCoachDataBody homecoachDataBody = netatmoBridgeHandler.getHomecoachDataBody(null); - if (homecoachDataBody != null) { - homecoachDataBody.getDevices().forEach(homecoach -> { + netatmoBridgeHandler.getHomecoachDataBody(null).ifPresent(dataBody -> { + dataBody.getDevices().forEach(homecoach -> { discoverHomeCoach(homecoach); }); - } + }); } if (netatmoBridgeHandler.configuration.readThermostat) { - NAThermostatDataBody thermostatsDataBody = netatmoBridgeHandler.getThermostatsDataBody(null); - if (thermostatsDataBody != null) { - thermostatsDataBody.getDevices().forEach(plug -> { + netatmoBridgeHandler.getThermostatsDataBody(null).ifPresent(dataBody -> { + dataBody.getDevices().forEach(plug -> { discoverThermostat(plug); }); - } + }); } if (netatmoBridgeHandler.configuration.readWelcome || netatmoBridgeHandler.configuration.readPresence) { - NAWelcomeHomeData welcomeHomeData = netatmoBridgeHandler.getWelcomeDataBody(null); - if (welcomeHomeData != null) { - welcomeHomeData.getHomes().forEach(home -> { + netatmoBridgeHandler.getWelcomeDataBody(null).ifPresent(dataBody -> { + dataBody.getHomes().forEach(home -> { discoverWelcomeHome(home); }); - } + }); } stopScan(); } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/AbstractNetatmoThingHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/AbstractNetatmoThingHandler.java index aaa8e1d4fc47f..f038730743c88 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/AbstractNetatmoThingHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/AbstractNetatmoThingHandler.java @@ -27,7 +27,7 @@ import javax.measure.quantity.Speed; import javax.measure.quantity.Temperature; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; @@ -59,9 +59,8 @@ * @author Rob Nielsen - Added day, week, and month measurements to the weather station and modules * */ +@NonNullByDefault public abstract class AbstractNetatmoThingHandler extends BaseThingHandler { - private Logger logger = LoggerFactory.getLogger(AbstractNetatmoThingHandler.class); - // Units of measurement of the data delivered by the API public static final Unit API_TEMPERATURE_UNIT = SIUnits.CELSIUS; public static final Unit API_HUMIDITY_UNIT = SmartHomeUnits.PERCENT; @@ -72,14 +71,16 @@ public abstract class AbstractNetatmoThingHandler extends BaseThingHandler { public static final Unit API_CO2_UNIT = SmartHomeUnits.PARTS_PER_MILLION; public static final Unit API_NOISE_UNIT = SmartHomeUnits.DECIBEL; + private final Logger logger = LoggerFactory.getLogger(AbstractNetatmoThingHandler.class); + protected final TimeZoneProvider timeZoneProvider; protected final MeasurableChannels measurableChannels = new MeasurableChannels(); - protected Optional radioHelper; - protected Optional batteryHelper; - protected Configuration config; - protected NetatmoBridgeHandler bridgeHandler; + private @Nullable RadioHelper radioHelper; + private @Nullable BatteryHelper batteryHelper; + protected @Nullable Configuration config; + private @Nullable NetatmoBridgeHandler bridgeHandler; - AbstractNetatmoThingHandler(@NonNull Thing thing, final TimeZoneProvider timeZoneProvider) { + AbstractNetatmoThingHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { super(thing); this.timeZoneProvider = timeZoneProvider; } @@ -97,7 +98,7 @@ public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { initializeThing(bridgeStatusInfo.getStatus()); } - private void initializeThing(ThingStatus bridgeStatus) { + private void initializeThing(@Nullable ThingStatus bridgeStatus) { Bridge bridge = getBridge(); BridgeHandler bridgeHandler = bridge != null ? bridge.getHandler() : null; if (bridgeHandler != null && bridgeStatus != null) { @@ -105,11 +106,11 @@ private void initializeThing(ThingStatus bridgeStatus) { config = getThing().getConfiguration(); radioHelper = thing.getProperties().containsKey(PROPERTY_SIGNAL_LEVELS) - ? Optional.of(new RadioHelper(thing.getProperties().get(PROPERTY_SIGNAL_LEVELS))) - : Optional.empty(); + ? new RadioHelper(thing.getProperties().get(PROPERTY_SIGNAL_LEVELS)) + : null; batteryHelper = thing.getProperties().containsKey(PROPERTY_BATTERY_LEVELS) - ? Optional.of(new BatteryHelper(thing.getProperties().get(PROPERTY_BATTERY_LEVELS))) - : Optional.empty(); + ? new BatteryHelper(thing.getProperties().get(PROPERTY_BATTERY_LEVELS)) + : null; updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Pending parent object initialization"); initializeThing(); @@ -123,14 +124,14 @@ private void initializeThing(ThingStatus bridgeStatus) { protected abstract void initializeThing(); - protected State getNAThingProperty(@NonNull String channelId) { + protected State getNAThingProperty(String channelId) { Optional result; - result = batteryHelper.flatMap(helper -> helper.getNAThingProperty(channelId)); + result = getBatteryHelper().flatMap(helper -> helper.getNAThingProperty(channelId)); if (result.isPresent()) { return result.get(); } - result = radioHelper.flatMap(helper -> helper.getNAThingProperty(channelId)); + result = getRadioHelper().flatMap(helper -> helper.getNAThingProperty(channelId)); if (result.isPresent()) { return result.get(); } @@ -152,9 +153,7 @@ private void updateDataChannels() { String channelId = channel.getUID().getId(); if (isLinked(channelId)) { State state = getNAThingProperty(channelId); - if (state != null) { - updateState(channel.getUID(), state); - } + updateState(channel.getUID(), state); } }); } @@ -173,7 +172,7 @@ private void triggerEventChannels() { * * @param channelId channel id */ - protected void triggerChannelIfRequired(@NonNull String channelId) { + protected void triggerChannelIfRequired(String channelId) { } @Override @@ -196,30 +195,35 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } - protected NetatmoBridgeHandler getBridgeHandler() { + protected Optional getBridgeHandler() { if (bridgeHandler == null) { Bridge bridge = getBridge(); if (bridge != null) { bridgeHandler = (NetatmoBridgeHandler) bridge.getHandler(); } } - return bridgeHandler; + NetatmoBridgeHandler handler = bridgeHandler; + return handler != null ? Optional.of(handler) : Optional.empty(); } - public boolean matchesId(String searchedId) { + protected Optional findNAThing(@Nullable String searchedId) { + return getBridgeHandler().flatMap(handler -> handler.findNAThing(searchedId)); + } + + public boolean matchesId(@Nullable String searchedId) { return searchedId != null && searchedId.equalsIgnoreCase(getId()); } - protected String getId() { - if (config != null) { - String equipmentId = (String) config.get(EQUIPMENT_ID); - return equipmentId.toLowerCase(); - } else { - return null; + protected @Nullable String getId() { + Configuration conf = config; + Object equipmentId = conf != null ? conf.get(EQUIPMENT_ID) : null; + if (equipmentId instanceof String) { + return ((String) equipmentId).toLowerCase(); } + return null; } - protected void updateProperties(Integer firmware, String modelId) { + protected void updateProperties(@Nullable Integer firmware, @Nullable String modelId) { Map properties = editProperties(); if (firmware != null || modelId != null) { properties.put(Thing.PROPERTY_VENDOR, VENDOR); @@ -233,13 +237,22 @@ protected void updateProperties(Integer firmware, String modelId) { updateProperties(properties); } + protected Optional getRadioHelper() { + RadioHelper helper = radioHelper; + return helper != null ? Optional.of(helper) : Optional.empty(); + } + + protected Optional getBatteryHelper() { + BatteryHelper helper = batteryHelper; + return helper != null ? Optional.of(helper) : Optional.empty(); + } + public void updateMeasurements() { } - public void getMeasurements(String device, @Nullable String module, String scale, List types, + public void getMeasurements(@Nullable String device, @Nullable String module, String scale, List types, List channels, Map channelMeasurements) { - NetatmoBridgeHandler handler = getBridgeHandler(); - if (handler == null) { + if (!getBridgeHandler().isPresent() || device == null) { return; } @@ -247,7 +260,7 @@ public void getMeasurements(String device, @Nullable String module, String scale throw new IllegalArgumentException("types and channels lists are different sizes."); } - List measurements = handler.getStationMeasureResponses(device, module, scale, types); + List measurements = getBridgeHandler().get().getStationMeasureResponses(device, module, scale, types); if (measurements.size() != types.size()) { throw new IllegalArgumentException("types and measurements lists are different sizes."); } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoBridgeHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoBridgeHandler.java index da0fbc5868c8d..64d474d078f71 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoBridgeHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoBridgeHandler.java @@ -118,11 +118,12 @@ private void connectionSucceed() { updateStatus(ThingStatus.ONLINE); WelcomeWebHookServlet servlet = webHookServlet; String webHookURI = getWebHookURI(); - WelcomeApi welcomeApi = getWelcomeApi(); - if (welcomeApi != null && servlet != null && webHookURI != null) { - servlet.activate(this); - logger.debug("Setting up Netatmo Welcome WebHook"); - welcomeApi.addwebhook(webHookURI, WEBHOOK_APP); + if (servlet != null && webHookURI != null) { + getWelcomeApi().ifPresent(api -> { + servlet.activate(this); + logger.debug("Setting up Netatmo Welcome WebHook"); + api.addwebhook(webHookURI, WEBHOOK_APP); + }); } } @@ -230,24 +231,24 @@ public void handleCommand(ChannelUID channelUID, Command command) { return map != null ? (PartnerApi) map.get(PartnerApi.class) : null; } - private @Nullable StationApi getStationApi() { + public Optional getStationApi() { APIMap map = apiMap; - return map != null ? (StationApi) map.get(StationApi.class) : null; + return map != null ? Optional.of((StationApi) map.get(StationApi.class)) : Optional.empty(); } - private @Nullable HealthyhomecoachApi getHomeCoachApi() { + public Optional getHomeCoachApi() { APIMap map = apiMap; - return map != null ? (HealthyhomecoachApi) map.get(HealthyhomecoachApi.class) : null; + return map != null ? Optional.of((HealthyhomecoachApi) map.get(HealthyhomecoachApi.class)) : Optional.empty(); } - public @Nullable ThermostatApi getThermostatApi() { + public Optional getThermostatApi() { APIMap map = apiMap; - return map != null ? (ThermostatApi) map.get(ThermostatApi.class) : null; + return map != null ? Optional.of((ThermostatApi) map.get(ThermostatApi.class)) : Optional.empty(); } - public @Nullable WelcomeApi getWelcomeApi() { + public Optional getWelcomeApi() { APIMap map = apiMap; - return map != null ? (WelcomeApi) map.get(WelcomeApi.class) : null; + return map != null ? Optional.of((WelcomeApi) map.get(WelcomeApi.class)) : Optional.empty(); } @Override @@ -255,11 +256,12 @@ public void dispose() { logger.debug("Running dispose()"); WelcomeWebHookServlet servlet = webHookServlet; - WelcomeApi welcomeApi = getWelcomeApi(); - if (welcomeApi != null && servlet != null && getWebHookURI() != null) { - logger.debug("Releasing Netatmo Welcome WebHook"); - servlet.deactivate(); - welcomeApi.dropwebhook(WEBHOOK_APP); + if (servlet != null && getWebHookURI() != null) { + getWelcomeApi().ifPresent(api -> { + logger.debug("Releasing Netatmo Welcome WebHook"); + servlet.deactivate(); + api.dropwebhook(WEBHOOK_APP); + }); } ScheduledFuture job = refreshJob; @@ -269,44 +271,39 @@ public void dispose() { } } - public @Nullable NAStationDataBody getStationsDataBody(@Nullable String equipmentId) { - StationApi stationApi = getStationApi(); - NAStationDataBody data = stationApi == null ? null : stationApi.getstationsdata(equipmentId, false).getBody(); + public Optional getStationsDataBody(@Nullable String equipmentId) { + Optional data = getStationApi() + .map(api -> api.getstationsdata(equipmentId, false).getBody()); updateStatus(ThingStatus.ONLINE); return data; } public List getStationMeasureResponses(String equipmentId, @Nullable String moduleId, String scale, List types) { - StationApi stationApi = getStationApi(); - List data = stationApi == null ? null - : stationApi - .getmeasure(equipmentId, scale, new CSVParams(types), moduleId, null, "last", 1, true, false) - .getBody(); + List data = getStationApi().map(api -> api + .getmeasure(equipmentId, scale, new CSVParams(types), moduleId, null, "last", 1, true, false).getBody()) + .orElse(null); updateStatus(ThingStatus.ONLINE); NAMeasureBodyElem element = (data != null && data.size() > 0) ? data.get(0) : null; return element != null ? element.getValue().get(0) : Collections.emptyList(); } - public @Nullable NAHealthyHomeCoachDataBody getHomecoachDataBody(@Nullable String equipmentId) { - HealthyhomecoachApi healthyhomecoachApi = getHomeCoachApi(); - NAHealthyHomeCoachDataBody data = healthyhomecoachApi == null ? null - : healthyhomecoachApi.gethomecoachsdata(equipmentId).getBody(); + public Optional getHomecoachDataBody(@Nullable String equipmentId) { + Optional data = getHomeCoachApi() + .map(api -> api.gethomecoachsdata(equipmentId).getBody()); updateStatus(ThingStatus.ONLINE); return data; } - public @Nullable NAThermostatDataBody getThermostatsDataBody(@Nullable String equipmentId) { - ThermostatApi thermostatApi = getThermostatApi(); - NAThermostatDataBody data = thermostatApi == null ? null - : thermostatApi.getthermostatsdata(equipmentId).getBody(); + public Optional getThermostatsDataBody(@Nullable String equipmentId) { + Optional data = getThermostatApi() + .map(api -> api.getthermostatsdata(equipmentId).getBody()); updateStatus(ThingStatus.ONLINE); return data; } - public @Nullable NAWelcomeHomeData getWelcomeDataBody(@Nullable String homeId) { - WelcomeApi welcomeApi = getWelcomeApi(); - NAWelcomeHomeData data = welcomeApi == null ? null : welcomeApi.gethomedata(homeId, null).getBody(); + public Optional getWelcomeDataBody(@Nullable String homeId) { + Optional data = getWelcomeApi().map(api -> api.gethomedata(homeId, null).getBody()); updateStatus(ThingStatus.ONLINE); return data; } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoDeviceHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoDeviceHandler.java index 37f2ef5769fd8..39476bb1d062e 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoDeviceHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoDeviceHandler.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.PointType; @@ -56,7 +57,7 @@ public abstract class NetatmoDeviceHandler extends AbstractNetatmoThingH private final Logger logger = LoggerFactory.getLogger(NetatmoDeviceHandler.class); private @Nullable ScheduledFuture refreshJob; private @Nullable RefreshStrategy refreshStrategy; - protected @Nullable DEVICE device; + private @Nullable DEVICE device; protected Map childs = new ConcurrentHashMap<>(); public NetatmoDeviceHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { @@ -81,7 +82,6 @@ private void scheduleRefreshJob() { updateChannels(); ScheduledFuture job = refreshJob; if (job != null) { - logger.debug("cancel refresh job"); job.cancel(false); refreshJob = null; } @@ -94,13 +94,12 @@ public void dispose() { logger.debug("Running dispose()"); ScheduledFuture job = refreshJob; if (job != null) { - logger.debug("cancel refresh job"); job.cancel(true); refreshJob = null; } } - protected abstract @Nullable DEVICE updateReadings(); + protected abstract Optional updateReadings(); protected void updateProperties(DEVICE deviceData) { } @@ -114,8 +113,7 @@ protected void updateChannels() { logger.debug("Trying to update channels on device {}", getId()); childs.clear(); - @Nullable - DEVICE newDeviceReading = null; + Optional newDeviceReading = Optional.empty(); try { newDeviceReading = updateReadings(); } catch (RetrofitError e) { @@ -128,33 +126,28 @@ protected void updateChannels() { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Unable to connect Netatmo API : " + e.getLocalizedMessage()); } - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - if (newDeviceReading != null) { + if (newDeviceReading.isPresent()) { updateStatus(ThingStatus.ONLINE); logger.debug("Successfully updated device {} readings! Now updating channels", getId()); - DEVICE theDevice = newDeviceReading; + DEVICE theDevice = newDeviceReading.get(); this.device = theDevice; updateProperties(theDevice); - Integer dataTimeStamp = getDataTimestamp(); - if (dataTimeStamp != null) { + getDataTimestamp().ifPresent(dataTimeStamp -> { strategy.setDataTimeStamp(dataTimeStamp, timeZoneProvider.getTimeZone()); - } - radioHelper.ifPresent(helper -> helper.setModule(theDevice)); - if (bridgeHandler != null) { - bridgeHandler.checkForNewThings(newDeviceReading); - } + }); + getRadioHelper().ifPresent(helper -> helper.setModule(theDevice)); + getBridgeHandler().ifPresent(handler -> { + handler.checkForNewThings(theDevice); + }); } else { logger.debug("Failed to update device {} readings! Skip updating channels", getId()); } // Be sure that all channels for the modules will be updated with refreshed data - if (bridgeHandler != null) { - childs.forEach((childId, moduleData) -> { - Optional childHandler = bridgeHandler.findNAThing(childId); - childHandler.map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> { - naChildModule.setRefreshRequired(true); - }); + childs.forEach((childId, moduleData) -> { + findNAThing(childId).map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> { + naChildModule.setRefreshRequired(true); }); - } + }); } else { logger.debug("Data still valid for device {}", getId()); } @@ -166,21 +159,19 @@ protected void updateChannels() { @Override protected State getNAThingProperty(String channelId) { try { - @Nullable - DEVICE theDevice = device; switch (channelId) { case CHANNEL_LAST_STATUS_STORE: - if (theDevice != null) { - Method getLastStatusStore = theDevice.getClass().getMethod("getLastStatusStore"); - Integer lastStatusStore = (Integer) getLastStatusStore.invoke(theDevice); + if (getDevice().isPresent()) { + Method getLastStatusStore = getDevice().get().getClass().getMethod("getLastStatusStore"); + Integer lastStatusStore = (Integer) getLastStatusStore.invoke(getDevice().get()); return ChannelTypeUtils.toDateTimeType(lastStatusStore, timeZoneProvider.getTimeZone()); } else { return UnDefType.UNDEF; } case CHANNEL_LOCATION: - if (theDevice != null) { - Method getPlace = theDevice.getClass().getMethod("getPlace"); - NAPlace place = (NAPlace) getPlace.invoke(theDevice); + if (getDevice().isPresent()) { + Method getPlace = getDevice().get().getClass().getMethod("getPlace"); + NAPlace place = (NAPlace) getPlace.invoke(getDevice().get()); PointType point = new PointType(new DecimalType(place.getLocation().get(1)), new DecimalType(place.getLocation().get(0))); if (place.getAltitude() != null) { @@ -200,17 +191,13 @@ protected State getNAThingProperty(String channelId) { } private void updateChildModules() { - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - if (bridgeHandler != null) { - logger.debug("Updating child modules of {}", getId()); - childs.forEach((childId, moduleData) -> { - Optional childHandler = bridgeHandler.findNAThing(childId); - childHandler.map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> { - logger.debug("Updating child module {}", naChildModule.getId()); - naChildModule.updateChannels(moduleData); - }); + logger.debug("Updating child modules of {}", getId()); + childs.forEach((childId, moduleData) -> { + findNAThing(childId).map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> { + logger.debug("Updating child module {}", naChildModule.getId()); + naChildModule.updateChannels(moduleData); }); - } + }); } /* @@ -227,7 +214,8 @@ private void defineRefreshInterval() { dataValidityPeriod = new BigDecimal(refreshPeriodProperty); } } else { - Object interval = config.get(REFRESH_INTERVAL); + Configuration conf = config; + Object interval = conf != null ? conf.get(REFRESH_INTERVAL) : null; if (interval instanceof BigDecimal) { dataValidityPeriod = (BigDecimal) interval; if (dataValidityPeriod.intValue() < MIN_REFRESH_INTERVAL) { @@ -243,7 +231,7 @@ private void defineRefreshInterval() { refreshStrategy = new RefreshStrategy(dataValidityPeriod.intValue()); } - protected abstract @Nullable Integer getDataTimestamp(); + protected abstract Optional getDataTimestamp(); public void expireData() { RefreshStrategy strategy = refreshStrategy; @@ -251,4 +239,8 @@ public void expireData() { strategy.expireData(); } } + + protected Optional getDevice() { + return Optional.ofNullable(device); + } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoModuleHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoModuleHandler.java index 7d59e1bf9d67d..adaf20a0dd3bd 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoModuleHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoModuleHandler.java @@ -20,8 +20,9 @@ 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.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingStatus; @@ -37,11 +38,11 @@ * * @author Gaƫl L'hopital - Initial contribution */ +@NonNullByDefault public class NetatmoModuleHandler extends AbstractNetatmoThingHandler { private final Logger logger = LoggerFactory.getLogger(NetatmoModuleHandler.class); - private ScheduledFuture refreshJob; - @Nullable - protected MODULE module; + private @Nullable ScheduledFuture refreshJob; + private @Nullable MODULE module; private boolean refreshRequired; protected NetatmoModuleHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { @@ -57,15 +58,20 @@ protected void initializeThing() { @Override public void dispose() { - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); + ScheduledFuture job = refreshJob; + if (job != null) { + job.cancel(true); refreshJob = null; } } - protected String getParentId() { - String parentId = (String) config.get(PARENT_ID); - return parentId.toLowerCase(); + protected @Nullable String getParentId() { + Configuration conf = config; + Object parentId = conf != null ? conf.get(PARENT_ID) : null; + if (parentId instanceof String) { + return ((String) parentId).toLowerCase(); + } + return null; } public boolean childOf(AbstractNetatmoThingHandler naThingHandler) { @@ -73,11 +79,11 @@ public boolean childOf(AbstractNetatmoThingHandler naThingHandler) { } @Override - protected State getNAThingProperty(@NonNull String channelId) { + protected State getNAThingProperty(String channelId) { try { - if (channelId.equalsIgnoreCase(CHANNEL_LAST_MESSAGE) && module != null) { - Method getLastMessage = module.getClass().getMethod("getLastMessage"); - Integer lastMessage = (Integer) getLastMessage.invoke(module); + if (channelId.equalsIgnoreCase(CHANNEL_LAST_MESSAGE) && getModule().isPresent()) { + Method getLastMessage = getModule().get().getClass().getMethod("getLastMessage"); + Integer lastMessage = (Integer) getLastMessage.invoke(getModule().get()); return ChannelTypeUtils.toDateTimeType(lastMessage, timeZoneProvider.getTimeZone()); } } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException @@ -89,16 +95,14 @@ protected State getNAThingProperty(@NonNull String channelId) { return super.getNAThingProperty(channelId); } - @SuppressWarnings("unchecked") protected void updateChannels(Object module) { - if (module != null) { - this.module = (MODULE) module; - updateStatus(ThingStatus.ONLINE); - radioHelper.ifPresent(helper -> helper.setModule(module)); - batteryHelper.ifPresent(helper -> helper.setModule(module)); - updateProperties(this.module); - super.updateChannels(); - } + MODULE theModule = (MODULE) module; + setModule(theModule); + updateStatus(ThingStatus.ONLINE); + getRadioHelper().ifPresent(helper -> helper.setModule(module)); + getBatteryHelper().ifPresent(helper -> helper.setModule(module)); + updateProperties(theModule); + super.updateChannels(); } protected void invalidateParentCacheAndRefresh() { @@ -112,13 +116,11 @@ protected void invalidateParentCacheAndRefresh() { protected void requestParentRefresh() { setRefreshRequired(true); - Optional parent = getBridgeHandler().findNAThing(getParentId()); - parent.ifPresent(AbstractNetatmoThingHandler::updateChannels); + findNAThing(getParentId()).ifPresent(AbstractNetatmoThingHandler::updateChannels); } private void invalidateParentCache() { - Optional parent = getBridgeHandler().findNAThing(getParentId()); - parent.map(NetatmoDeviceHandler.class::cast).ifPresent(NetatmoDeviceHandler::expireData); + findNAThing(getParentId()).map(NetatmoDeviceHandler.class::cast).ifPresent(NetatmoDeviceHandler::expireData); } protected void updateProperties(MODULE moduleData) { @@ -132,7 +134,11 @@ protected void setRefreshRequired(boolean refreshRequired) { this.refreshRequired = refreshRequired; } - protected @NonNull Optional getModule() { + protected Optional getModule() { return Optional.ofNullable(module); } + + public void setModule(MODULE module) { + this.module = module; + } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/homecoach/NAHealthyHomeCoachHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/homecoach/NAHealthyHomeCoachHandler.java index a8f78bd4aec59..e61da9f3cfcab 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/homecoach/NAHealthyHomeCoachHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/homecoach/NAHealthyHomeCoachHandler.java @@ -15,17 +15,17 @@ import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*; import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; +import java.util.Optional; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.types.State; -import org.openhab.binding.netatmo.internal.handler.NetatmoBridgeHandler; import org.openhab.binding.netatmo.internal.handler.NetatmoDeviceHandler; import io.swagger.client.model.NADashboardData; import io.swagger.client.model.NAHealthyHomeCoach; -import io.swagger.client.model.NAHealthyHomeCoachDataBody; /** * {@link NAHealthyHomeCoachHandler} is the class used to handle the Health Home Coach device @@ -41,15 +41,9 @@ public NAHealthyHomeCoachHandler(Thing thing, final TimeZoneProvider timeZonePro } @Override - protected @Nullable NAHealthyHomeCoach updateReadings() { - NAHealthyHomeCoach result = null; - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - NAHealthyHomeCoachDataBody homecoachDataBody = bridgeHandler == null ? null - : bridgeHandler.getHomecoachDataBody(getId()); - if (homecoachDataBody != null) { - result = homecoachDataBody.getDevices().get(0); - } - return result; + protected Optional updateReadings() { + return getBridgeHandler().flatMap(handler -> handler.getHomecoachDataBody(getId())) + .map(dataBody -> dataBody.getDevices().get(0)); } @Override @@ -59,9 +53,8 @@ protected void updateProperties(NAHealthyHomeCoach deviceData) { @Override protected State getNAThingProperty(String channelId) { - NAHealthyHomeCoach healthyHomeCoachDevice = device; - if (healthyHomeCoachDevice != null) { - NADashboardData dashboardData = healthyHomeCoachDevice.getDashboardData(); + NADashboardData dashboardData = getDevice().map(d -> d.getDashboardData()).orElse(null); + if (dashboardData != null) { switch (channelId) { case CHANNEL_CO2: return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT); @@ -117,14 +110,7 @@ protected State getNAThingProperty(String channelId) { } @Override - protected @Nullable Integer getDataTimestamp() { - NAHealthyHomeCoach healthyHomeCoachDevice = device; - if (healthyHomeCoachDevice != null) { - Integer lastStored = healthyHomeCoachDevice.getLastStatusStore(); - if (lastStored != null) { - return lastStored; - } - } - return null; + protected Optional getDataTimestamp() { + return getDevice().map(d -> d.getLastStatusStore()); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandler.java index 5c0250b852c6a..2a737bcbe1f36 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandler.java @@ -13,9 +13,10 @@ package org.openhab.binding.netatmo.internal.presence; import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.toOnOffType; +import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; + +import java.util.Optional; -import io.swagger.client.model.NAWelcomeCamera; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.OnOffType; @@ -26,10 +27,7 @@ import org.eclipse.smarthome.core.types.UnDefType; import org.openhab.binding.netatmo.internal.camera.CameraHandler; -import java.util.Optional; - -import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT; -import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE; +import io.swagger.client.model.NAWelcomeCamera; /** * {@link NAPresenceCameraHandler} is the class used to handle Presence camera data @@ -70,13 +68,14 @@ public void handleCommand(ChannelUID channelUID, Command command) { } @Override - protected State getNAThingProperty(@NonNull String channelId) { + protected State getNAThingProperty(String channelId) { switch (channelId) { case CHANNEL_CAMERA_FLOODLIGHT: return getFloodlightState(); case CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE: - //The auto-mode state shouldn't be updated, because this isn't a dedicated information. When the - // floodlight is switched on the state within the Netatmo API is "on" and the information if the previous + // The auto-mode state shouldn't be updated, because this isn't a dedicated information. When the + // floodlight is switched on the state within the Netatmo API is "on" and the information if the + // previous // state was "auto" instead of "off" is lost... Therefore the binding handles its own auto-mode state. if (floodlightAutoModeState == UnDefType.UNDEF) { floodlightAutoModeState = getFloodlightAutoModeState(); @@ -87,14 +86,12 @@ protected State getNAThingProperty(@NonNull String channelId) { } private State getFloodlightState() { - return getModule() - .map(m -> toOnOffType(m.getLightModeStatus() == NAWelcomeCamera.LightModeStatusEnum.ON)) + return getModule().map(m -> toOnOffType(m.getLightModeStatus() == NAWelcomeCamera.LightModeStatusEnum.ON)) .orElse(UnDefType.UNDEF); } private State getFloodlightAutoModeState() { - return getModule() - .map(m -> toOnOffType(m.getLightModeStatus() == NAWelcomeCamera.LightModeStatusEnum.AUTO)) + return getModule().map(m -> toOnOffType(m.getLightModeStatus() == NAWelcomeCamera.LightModeStatusEnum.AUTO)) .orElse(UnDefType.UNDEF); } @@ -118,10 +115,7 @@ private void switchFloodlightAutoMode(boolean isAutoMode) { private void changeFloodlightMode(NAWelcomeCamera.LightModeStatusEnum mode) { Optional localCameraURL = getLocalCameraURL(); if (localCameraURL.isPresent()) { - String url = localCameraURL.get() - + FLOODLIGHT_SET_URL_PATH - + "?config=%7B%22mode%22:%22" - + mode.toString() + String url = localCameraURL.get() + FLOODLIGHT_SET_URL_PATH + "?config=%7B%22mode%22:%22" + mode.toString() + "%22%7D"; executeGETRequest(url); diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAMainHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAMainHandler.java index b0e07fb3c85f9..5ef238a78f202 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAMainHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAMainHandler.java @@ -22,19 +22,15 @@ import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.types.State; import org.openhab.binding.netatmo.internal.WeatherUtils; -import org.openhab.binding.netatmo.internal.handler.AbstractNetatmoThingHandler; -import org.openhab.binding.netatmo.internal.handler.NetatmoBridgeHandler; import org.openhab.binding.netatmo.internal.handler.NetatmoDeviceHandler; import org.openhab.binding.netatmo.internal.handler.NetatmoModuleHandler; import io.swagger.client.model.NADashboardData; import io.swagger.client.model.NAMain; -import io.swagger.client.model.NAStationDataBody; /** * {@link NAMainHandler} is the base class for all current Netatmo @@ -53,28 +49,21 @@ public NAMainHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { } @Override - protected @Nullable NAMain updateReadings() { - NAMain result = null; - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - NAStationDataBody stationDataBody = bridgeHandler == null ? null : bridgeHandler.getStationsDataBody(getId()); - if (stationDataBody != null) { - result = stationDataBody.getDevices().stream().filter(device -> device.getId().equalsIgnoreCase(getId())) - .findFirst().orElse(null); - if (result != null) { - result.getModules().forEach(child -> childs.put(child.getId(), child)); - } - } + protected Optional updateReadings() { + Optional result = getBridgeHandler().flatMap(handler -> handler.getStationsDataBody(getId())) + .map(dataBody -> dataBody.getDevices().stream() + .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null)); + result.ifPresent(device -> { + device.getModules().forEach(child -> childs.put(child.getId(), child)); + }); updateMeasurements(); - if (bridgeHandler != null) { - childs.keySet().forEach((childId) -> { - Optional childHandler = bridgeHandler.findNAThing(childId); - childHandler.map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> { - naChildModule.updateMeasurements(); - }); + childs.keySet().forEach((childId) -> { + findNAThing(childId).map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> { + naChildModule.updateMeasurements(); }); - } + }); return result; } @@ -173,54 +162,51 @@ private void updateMonthMeasurements() { @Override protected State getNAThingProperty(String channelId) { - NAMain mainDevice = device; - if (mainDevice != null) { - NADashboardData dashboardData = mainDevice.getDashboardData(); - if (dashboardData != null) { - switch (channelId) { - case CHANNEL_CO2: - return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT); - case CHANNEL_TEMPERATURE: - return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT); - case CHANNEL_MIN_TEMP: - return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT); - case CHANNEL_MAX_TEMP: - return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT); - case CHANNEL_TEMP_TREND: - return toStringType(dashboardData.getTempTrend()); - case CHANNEL_NOISE: - return toQuantityType(dashboardData.getNoise(), API_NOISE_UNIT); - case CHANNEL_PRESSURE: - return toQuantityType(dashboardData.getPressure(), API_PRESSURE_UNIT); - case CHANNEL_PRESS_TREND: - return toStringType(dashboardData.getPressureTrend()); - case CHANNEL_ABSOLUTE_PRESSURE: - return toQuantityType(dashboardData.getAbsolutePressure(), API_PRESSURE_UNIT); - case CHANNEL_TIMEUTC: - return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); - case CHANNEL_DATE_MIN_TEMP: - return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone()); - case CHANNEL_DATE_MAX_TEMP: - return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone()); - case CHANNEL_HUMIDITY: - return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT); - case CHANNEL_HUMIDEX: - return toDecimalType( - WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity())); - case CHANNEL_HEATINDEX: - return toQuantityType( - WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()), - API_TEMPERATURE_UNIT); - case CHANNEL_DEWPOINT: - return toQuantityType( - WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()), - API_TEMPERATURE_UNIT); - case CHANNEL_DEWPOINTDEP: - Double dewPoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(), - dashboardData.getHumidity()); - return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewPoint), - API_TEMPERATURE_UNIT); - } + NADashboardData dashboardData = getDevice().map(d -> d.getDashboardData()).orElse(null); + if (dashboardData != null) { + switch (channelId) { + case CHANNEL_CO2: + return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT); + case CHANNEL_TEMPERATURE: + return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT); + case CHANNEL_MIN_TEMP: + return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT); + case CHANNEL_MAX_TEMP: + return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT); + case CHANNEL_TEMP_TREND: + return toStringType(dashboardData.getTempTrend()); + case CHANNEL_NOISE: + return toQuantityType(dashboardData.getNoise(), API_NOISE_UNIT); + case CHANNEL_PRESSURE: + return toQuantityType(dashboardData.getPressure(), API_PRESSURE_UNIT); + case CHANNEL_PRESS_TREND: + return toStringType(dashboardData.getPressureTrend()); + case CHANNEL_ABSOLUTE_PRESSURE: + return toQuantityType(dashboardData.getAbsolutePressure(), API_PRESSURE_UNIT); + case CHANNEL_TIMEUTC: + return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); + case CHANNEL_DATE_MIN_TEMP: + return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone()); + case CHANNEL_DATE_MAX_TEMP: + return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone()); + case CHANNEL_HUMIDITY: + return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT); + case CHANNEL_HUMIDEX: + return toDecimalType( + WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity())); + case CHANNEL_HEATINDEX: + return toQuantityType( + WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()), + API_TEMPERATURE_UNIT); + case CHANNEL_DEWPOINT: + return toQuantityType( + WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()), + API_TEMPERATURE_UNIT); + case CHANNEL_DEWPOINTDEP: + Double dewPoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(), + dashboardData.getHumidity()); + return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewPoint), + API_TEMPERATURE_UNIT); } } @@ -293,14 +279,7 @@ protected State getNAThingProperty(String channelId) { } @Override - protected @Nullable Integer getDataTimestamp() { - NAMain mainDevice = device; - if (mainDevice != null) { - Integer lastStored = mainDevice.getLastStatusStore(); - if (lastStored != null) { - return lastStored; - } - } - return null; + protected Optional getDataTimestamp() { + return getDevice().map(d -> d.getLastStatusStore()); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule1Handler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule1Handler.java index 80c814d521c1f..38e031525143a 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule1Handler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule1Handler.java @@ -104,44 +104,41 @@ private void updateMonthMeasurements() { @Override protected State getNAThingProperty(String channelId) { - NAStationModule stationModule = module; - if (stationModule != null) { - NADashboardData dashboardData = stationModule.getDashboardData(); - if (dashboardData != null) { - switch (channelId) { - case CHANNEL_TEMP_TREND: - return toStringType(dashboardData.getTempTrend()); - case CHANNEL_TEMPERATURE: - return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT); - case CHANNEL_DATE_MIN_TEMP: - return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone()); - case CHANNEL_DATE_MAX_TEMP: - return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone()); - case CHANNEL_MIN_TEMP: - return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT); - case CHANNEL_MAX_TEMP: - return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT); - case CHANNEL_HUMIDITY: - return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT); - case CHANNEL_TIMEUTC: - return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); - case CHANNEL_HUMIDEX: - return toDecimalType( - WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity())); - case CHANNEL_HEATINDEX: - return toQuantityType( - WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()), - API_TEMPERATURE_UNIT); - case CHANNEL_DEWPOINT: - return toQuantityType( - WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()), - API_TEMPERATURE_UNIT); - case CHANNEL_DEWPOINTDEP: - Double dewpoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(), - dashboardData.getHumidity()); - return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewpoint), - API_TEMPERATURE_UNIT); - } + NADashboardData dashboardData = getModule().map(m -> m.getDashboardData()).orElse(null); + if (dashboardData != null) { + switch (channelId) { + case CHANNEL_TEMP_TREND: + return toStringType(dashboardData.getTempTrend()); + case CHANNEL_TEMPERATURE: + return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT); + case CHANNEL_DATE_MIN_TEMP: + return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone()); + case CHANNEL_DATE_MAX_TEMP: + return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone()); + case CHANNEL_MIN_TEMP: + return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT); + case CHANNEL_MAX_TEMP: + return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT); + case CHANNEL_HUMIDITY: + return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT); + case CHANNEL_TIMEUTC: + return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); + case CHANNEL_HUMIDEX: + return toDecimalType( + WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity())); + case CHANNEL_HEATINDEX: + return toQuantityType( + WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()), + API_TEMPERATURE_UNIT); + case CHANNEL_DEWPOINT: + return toQuantityType( + WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()), + API_TEMPERATURE_UNIT); + case CHANNEL_DEWPOINTDEP: + Double dewpoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(), + dashboardData.getHumidity()); + return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewpoint), + API_TEMPERATURE_UNIT); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule2Handler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule2Handler.java index 459f36c566270..7965dec7abb61 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule2Handler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule2Handler.java @@ -44,26 +44,23 @@ protected void updateProperties(NAStationModule moduleData) { @Override protected State getNAThingProperty(String channelId) { - NAStationModule stationModule = module; - if (stationModule != null) { - NADashboardData dashboardData = stationModule.getDashboardData(); - if (dashboardData != null) { - switch (channelId) { - case CHANNEL_WIND_ANGLE: - return toQuantityType(dashboardData.getWindAngle(), API_WIND_DIRECTION_UNIT); - case CHANNEL_WIND_STRENGTH: - return toQuantityType(dashboardData.getWindStrength(), API_WIND_SPEED_UNIT); - case CHANNEL_GUST_ANGLE: - return toQuantityType(dashboardData.getGustAngle(), API_WIND_DIRECTION_UNIT); - case CHANNEL_GUST_STRENGTH: - return toQuantityType(dashboardData.getGustStrength(), API_WIND_SPEED_UNIT); - case CHANNEL_TIMEUTC: - return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); - case CHANNEL_MAX_WIND_STRENGTH: - return toQuantityType(dashboardData.getMaxWindStr(), API_WIND_SPEED_UNIT); - case CHANNEL_DATE_MAX_WIND_STRENGTH: - return toDateTimeType(dashboardData.getDateMaxWindStr(), timeZoneProvider.getTimeZone()); - } + NADashboardData dashboardData = getModule().map(m -> m.getDashboardData()).orElse(null); + if (dashboardData != null) { + switch (channelId) { + case CHANNEL_WIND_ANGLE: + return toQuantityType(dashboardData.getWindAngle(), API_WIND_DIRECTION_UNIT); + case CHANNEL_WIND_STRENGTH: + return toQuantityType(dashboardData.getWindStrength(), API_WIND_SPEED_UNIT); + case CHANNEL_GUST_ANGLE: + return toQuantityType(dashboardData.getGustAngle(), API_WIND_DIRECTION_UNIT); + case CHANNEL_GUST_STRENGTH: + return toQuantityType(dashboardData.getGustStrength(), API_WIND_SPEED_UNIT); + case CHANNEL_TIMEUTC: + return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); + case CHANNEL_MAX_WIND_STRENGTH: + return toQuantityType(dashboardData.getMaxWindStr(), API_WIND_SPEED_UNIT); + case CHANNEL_DATE_MAX_WIND_STRENGTH: + return toDateTimeType(dashboardData.getDateMaxWindStr(), timeZoneProvider.getTimeZone()); } } return super.getNAThingProperty(channelId); diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule3Handler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule3Handler.java index 556440bfd720c..afbc06ad5a0e0 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule3Handler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule3Handler.java @@ -67,20 +67,17 @@ public void updateMeasurements() { @Override protected State getNAThingProperty(String channelId) { - NAStationModule stationModule = module; - if (stationModule != null) { - NADashboardData dashboardData = stationModule.getDashboardData(); - if (dashboardData != null) { - switch (channelId) { - case CHANNEL_RAIN: - return toQuantityType(dashboardData.getRain(), API_RAIN_UNIT); - case CHANNEL_SUM_RAIN1: - return toQuantityType(dashboardData.getSumRain1(), API_RAIN_UNIT); - case CHANNEL_SUM_RAIN24: - return toQuantityType(dashboardData.getSumRain24(), API_RAIN_UNIT); - case CHANNEL_TIMEUTC: - return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); - } + NADashboardData dashboardData = getModule().map(m -> m.getDashboardData()).orElse(null); + if (dashboardData != null) { + switch (channelId) { + case CHANNEL_RAIN: + return toQuantityType(dashboardData.getRain(), API_RAIN_UNIT); + case CHANNEL_SUM_RAIN1: + return toQuantityType(dashboardData.getSumRain1(), API_RAIN_UNIT); + case CHANNEL_SUM_RAIN24: + return toQuantityType(dashboardData.getSumRain24(), API_RAIN_UNIT); + case CHANNEL_TIMEUTC: + return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule4Handler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule4Handler.java index a86f5a3fd663a..66a4b83ede63f 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule4Handler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule4Handler.java @@ -116,46 +116,43 @@ private void updateMonthMeasurements() { @Override protected State getNAThingProperty(String channelId) { - NAStationModule stationModule = module; - if (stationModule != null) { - NADashboardData dashboardData = stationModule.getDashboardData(); - if (dashboardData != null) { - switch (channelId) { - case CHANNEL_TEMP_TREND: - return toStringType(dashboardData.getTempTrend()); - case CHANNEL_CO2: - return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT); - case CHANNEL_TEMPERATURE: - return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT); - case CHANNEL_DATE_MIN_TEMP: - return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone()); - case CHANNEL_DATE_MAX_TEMP: - return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone()); - case CHANNEL_MIN_TEMP: - return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT); - case CHANNEL_MAX_TEMP: - return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT); - case CHANNEL_TIMEUTC: - return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); - case CHANNEL_HUMIDITY: - return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT); - case CHANNEL_HUMIDEX: - return toDecimalType( - WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity())); - case CHANNEL_HEATINDEX: - return toQuantityType( - WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()), - API_TEMPERATURE_UNIT); - case CHANNEL_DEWPOINT: - return toQuantityType( - WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()), - API_TEMPERATURE_UNIT); - case CHANNEL_DEWPOINTDEP: - Double dewpoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(), - dashboardData.getHumidity()); - return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewpoint), - API_TEMPERATURE_UNIT); - } + NADashboardData dashboardData = getModule().map(m -> m.getDashboardData()).orElse(null); + if (dashboardData != null) { + switch (channelId) { + case CHANNEL_TEMP_TREND: + return toStringType(dashboardData.getTempTrend()); + case CHANNEL_CO2: + return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT); + case CHANNEL_TEMPERATURE: + return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT); + case CHANNEL_DATE_MIN_TEMP: + return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone()); + case CHANNEL_DATE_MAX_TEMP: + return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone()); + case CHANNEL_MIN_TEMP: + return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT); + case CHANNEL_MAX_TEMP: + return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT); + case CHANNEL_TIMEUTC: + return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone()); + case CHANNEL_HUMIDITY: + return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT); + case CHANNEL_HUMIDEX: + return toDecimalType( + WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity())); + case CHANNEL_HEATINDEX: + return toQuantityType( + WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()), + API_TEMPERATURE_UNIT); + case CHANNEL_DEWPOINT: + return toQuantityType( + WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()), + API_TEMPERATURE_UNIT); + case CHANNEL_DEWPOINTDEP: + Double dewpoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(), + dashboardData.getHumidity()); + return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewpoint), + API_TEMPERATURE_UNIT); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NAPlugHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NAPlugHandler.java index 0ab3a2e0d2cb4..630c30fb73c84 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NAPlugHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NAPlugHandler.java @@ -17,6 +17,7 @@ import java.time.ZonedDateTime; import java.time.temporal.TemporalAdjusters; +import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -24,11 +25,9 @@ import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.types.State; import org.eclipse.smarthome.core.types.UnDefType; -import org.openhab.binding.netatmo.internal.handler.NetatmoBridgeHandler; import org.openhab.binding.netatmo.internal.handler.NetatmoDeviceHandler; import io.swagger.client.model.NAPlug; -import io.swagger.client.model.NAThermostatDataBody; import io.swagger.client.model.NAYearMonth; /** @@ -46,18 +45,13 @@ public NAPlugHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { } @Override - protected @Nullable NAPlug updateReadings() { - NAPlug result = null; - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - NAThermostatDataBody thermostatDataBody = bridgeHandler == null ? null - : bridgeHandler.getThermostatsDataBody(getId()); - if (thermostatDataBody != null) { - result = thermostatDataBody.getDevices().stream().filter(device -> device.getId().equalsIgnoreCase(getId())) - .findFirst().orElse(null); - if (result != null) { - result.getModules().forEach(child -> childs.put(child.getId(), child)); - } - } + protected Optional updateReadings() { + Optional result = getBridgeHandler().flatMap(handler -> handler.getThermostatsDataBody(getId())) + .map(dataBody -> dataBody.getDevices().stream() + .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null)); + result.ifPresent(device -> { + device.getModules().forEach(child -> childs.put(child.getId(), child)); + }); return result; } @@ -68,13 +62,12 @@ protected void updateProperties(NAPlug deviceData) { @Override protected State getNAThingProperty(String channelId) { - NAPlug plugDevice = device; switch (channelId) { case CHANNEL_CONNECTED_BOILER: - return plugDevice != null ? toOnOffType(plugDevice.getPlugConnectedBoiler()) : UnDefType.UNDEF; + return getDevice().map(d -> toOnOffType(d.getPlugConnectedBoiler())).orElse(UnDefType.UNDEF); case CHANNEL_LAST_PLUG_SEEN: - return plugDevice != null ? toDateTimeType(plugDevice.getLastPlugSeen(), timeZoneProvider.getTimeZone()) - : UnDefType.UNDEF; + return getDevice().map(d -> toDateTimeType(d.getLastPlugSeen(), timeZoneProvider.getTimeZone())) + .orElse(UnDefType.UNDEF); case CHANNEL_LAST_BILAN: return toDateTimeType(getLastBilan()); } @@ -82,27 +75,17 @@ protected State getNAThingProperty(String channelId) { } public @Nullable ZonedDateTime getLastBilan() { - NAPlug plugDevice = device; - if (plugDevice != null) { - NAYearMonth lastBilan = plugDevice.getLastBilan(); - if (lastBilan != null) { - ZonedDateTime zonedDT = ZonedDateTime.of(lastBilan.getY(), lastBilan.getM(), 1, 0, 0, 0, 0, - ZonedDateTime.now().getZone()); - return zonedDT.with(TemporalAdjusters.lastDayOfMonth()); - } + Optional lastBilan = getDevice().map(d -> d.getLastBilan()); + if (lastBilan.isPresent()) { + ZonedDateTime zonedDT = ZonedDateTime.of(lastBilan.get().getY(), lastBilan.get().getM(), 1, 0, 0, 0, 0, + ZonedDateTime.now().getZone()); + return zonedDT.with(TemporalAdjusters.lastDayOfMonth()); } return null; } @Override - protected @Nullable Integer getDataTimestamp() { - NAPlug plugDevice = device; - if (plugDevice != null) { - Integer lastStored = plugDevice.getLastStatusStore(); - if (lastStored != null) { - return lastStored; - } - } - return null; + protected Optional getDataTimestamp() { + return getDevice().map(d -> d.getLastStatusStore()); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NATherm1Handler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NATherm1Handler.java index 843af819ec97a..d90306ba32fa6 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NATherm1Handler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NATherm1Handler.java @@ -27,6 +27,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.types.QuantityType; @@ -41,7 +42,6 @@ import org.eclipse.smarthome.core.types.StateOption; import org.eclipse.smarthome.core.types.UnDefType; import org.openhab.binding.netatmo.internal.NATherm1StateDescriptionProvider; -import org.openhab.binding.netatmo.internal.handler.NetatmoBridgeHandler; import org.openhab.binding.netatmo.internal.handler.NetatmoModuleHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,30 +77,21 @@ protected void updateProperties(NAThermostat moduleData) { updateProperties(moduleData.getFirmware(), moduleData.getType()); } - private @Nullable ThermostatApi getThermostatApi() { - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - return bridgeHandler == null ? null : bridgeHandler.getThermostatApi(); - } - @Override - public void updateChannels(@Nullable Object moduleObject) { + public void updateChannels(Object moduleObject) { if (isRefreshRequired()) { measurableChannels.getAsCsv().ifPresent(csvParams -> { - ThermostatApi thermostatApi = getThermostatApi(); - if (thermostatApi != null) { - NAMeasureResponse measures = thermostatApi.getmeasure(getParentId(), "max", csvParams, getId(), - null, null, 1, true, true); + getApi().ifPresent(api -> { + NAMeasureResponse measures = api.getmeasure(getParentId(), "max", csvParams, getId(), null, null, 1, + true, true); measurableChannels.setMeasures(measures); - } + }); }); setRefreshRequired(false); } super.updateChannels(moduleObject); - NAThermostat thermostat = module; - if (thermostat != null) { - updateStateDescription(thermostat); - } + getModule().ifPresent(this::updateStateDescription); } private void updateStateDescription(NAThermostat thermostat) { @@ -113,30 +104,27 @@ private void updateStateDescription(NAThermostat thermostat) { @Override protected State getNAThingProperty(String channelId) { - NAThermostat thermostat = module; switch (channelId) { case CHANNEL_THERM_ORIENTATION: - return thermostat != null ? toDecimalType(thermostat.getThermOrientation()) : UnDefType.UNDEF; + return getModule().map(m -> toDecimalType(m.getThermOrientation())).orElse(UnDefType.UNDEF); case CHANNEL_THERM_RELAY: - return thermostat != null ? thermostat.getThermRelayCmd() == 100 ? OnOffType.ON : OnOffType.OFF - : UnDefType.UNDEF; + return getModule().map(m -> m.getThermRelayCmd() == 100 ? (State) OnOffType.ON : (State) OnOffType.OFF) + .orElse(UnDefType.UNDEF); case CHANNEL_TEMPERATURE: - return thermostat != null - ? toQuantityType(thermostat.getMeasured().getTemperature(), API_TEMPERATURE_UNIT) - : UnDefType.UNDEF; + return getModule().map(m -> toQuantityType(m.getMeasured().getTemperature(), API_TEMPERATURE_UNIT)) + .orElse(UnDefType.UNDEF); case CHANNEL_SETPOINT_TEMP: return getCurrentSetpoint(); case CHANNEL_TIMEUTC: - return thermostat != null - ? toDateTimeType(thermostat.getMeasured().getTime(), timeZoneProvider.getTimeZone()) - : UnDefType.UNDEF; + return getModule().map(m -> toDateTimeType(m.getMeasured().getTime(), timeZoneProvider.getTimeZone())) + .orElse(UnDefType.UNDEF); case CHANNEL_SETPOINT_END_TIME: { - if (thermostat != null) { - NASetpoint setpoint = thermostat.getSetpoint(); + if (getModule().isPresent()) { + NASetpoint setpoint = getModule().get().getSetpoint(); if (setpoint != null) { Integer endTime = setpoint.getSetpointEndtime(); if (endTime == null) { - endTime = getNextProgramTime(thermostat.getThermProgramList()); + endTime = getNextProgramTime(getModule().get().getThermProgramList()); } return toDateTimeType(endTime, timeZoneProvider.getTimeZone()); } @@ -148,53 +136,54 @@ protected State getNAThingProperty(String channelId) { return getSetpoint(); case CHANNEL_PLANNING: { String currentPlanning = "-"; - if (thermostat != null) { - for (NAThermProgram program : thermostat.getThermProgramList()) { + if (getModule().isPresent()) { + for (NAThermProgram program : getModule().get().getThermProgramList()) { if (program.getSelected() == Boolean.TRUE) { currentPlanning = program.getProgramId(); } } return toStringType(currentPlanning); } + return UnDefType.UNDEF; } } return super.getNAThingProperty(channelId); } private State getSetpoint() { - NAThermostat thermostat = module; - return thermostat != null - ? thermostat.getSetpoint() != null ? toStringType(thermostat.getSetpoint().getSetpointMode()) - : UnDefType.NULL - : UnDefType.UNDEF; + return getModule() + .map(m -> m.getSetpoint() != null ? toStringType(m.getSetpoint().getSetpointMode()) : UnDefType.NULL) + .orElse(UnDefType.UNDEF); } private State getCurrentSetpoint() { - NAThermostat thermostat = module; - if (thermostat != null && thermostat.getSetpoint() != null) { - NASetpoint setPoint = thermostat.getSetpoint(); - String currentMode = setPoint.getSetpointMode(); - - NAThermProgram currentProgram = thermostat.getThermProgramList().stream() - .filter(p -> p.getSelected() != null && p.getSelected()).findFirst().get(); - switch (currentMode) { - case CHANNEL_SETPOINT_MODE_MANUAL: - return toDecimalType(setPoint.getSetpointTemp()); - case CHANNEL_SETPOINT_MODE_AWAY: - NAZone zone = getZone(currentProgram.getZones(), 2); - return toDecimalType(zone.getTemp()); - case CHANNEL_SETPOINT_MODE_HG: - NAZone zone1 = getZone(currentProgram.getZones(), 3); - return toDecimalType(zone1.getTemp()); - case CHANNEL_SETPOINT_MODE_PROGRAM: - NATimeTableItem currentProgramMode = getCurrentProgramMode(thermostat.getThermProgramList()); - if (currentProgramMode != null) { - NAZone zone2 = getZone(currentProgram.getZones(), currentProgramMode.getId()); - return toDecimalType(zone2.getTemp()); - } - case CHANNEL_SETPOINT_MODE_OFF: - case CHANNEL_SETPOINT_MODE_MAX: - return UnDefType.UNDEF; + if (getModule().isPresent()) { + NASetpoint setPoint = getModule().get().getSetpoint(); + if (setPoint != null) { + String currentMode = setPoint.getSetpointMode(); + + NAThermProgram currentProgram = getModule().get().getThermProgramList().stream() + .filter(p -> p.getSelected() != null && p.getSelected()).findFirst().get(); + switch (currentMode) { + case CHANNEL_SETPOINT_MODE_MANUAL: + return toDecimalType(setPoint.getSetpointTemp()); + case CHANNEL_SETPOINT_MODE_AWAY: + NAZone zone = getZone(currentProgram.getZones(), 2); + return toDecimalType(zone.getTemp()); + case CHANNEL_SETPOINT_MODE_HG: + NAZone zone1 = getZone(currentProgram.getZones(), 3); + return toDecimalType(zone1.getTemp()); + case CHANNEL_SETPOINT_MODE_PROGRAM: + NATimeTableItem currentProgramMode = getCurrentProgramMode( + getModule().get().getThermProgramList()); + if (currentProgramMode != null) { + NAZone zone2 = getZone(currentProgram.getZones(), currentProgramMode.getId()); + return toDecimalType(zone2.getTemp()); + } + case CHANNEL_SETPOINT_MODE_OFF: + case CHANNEL_SETPOINT_MODE_MAX: + return UnDefType.UNDEF; + } } } return UnDefType.NULL; @@ -294,12 +283,11 @@ public void handleCommand(ChannelUID channelUID, Command command) { break; } case CHANNEL_PLANNING: { - ThermostatApi thermostatApi = getThermostatApi(); - if (thermostatApi != null) { - thermostatApi.switchschedule(getParentId(), getId(), command.toString()); + getApi().ifPresent(api -> { + api.switchschedule(getParentId(), getId(), command.toString()); updateState(channelUID, new StringType(command.toString())); invalidateParentCacheAndRefresh(); - } + }); } } } catch (Exception e) { @@ -310,11 +298,10 @@ public void handleCommand(ChannelUID channelUID, Command command) { private void pushSetpointUpdate(String target_mode, @Nullable Integer setpointEndtime, @Nullable Float setpointTemp) { - ThermostatApi thermostatApi = getThermostatApi(); - if (thermostatApi != null) { - thermostatApi.setthermpoint(getParentId(), getId(), target_mode, setpointEndtime, setpointTemp); + getApi().ifPresent(api -> { + api.setthermpoint(getParentId(), getId(), target_mode, setpointEndtime, setpointTemp); invalidateParentCacheAndRefresh(); - } + }); } private int getSetpointEndTime() { @@ -327,6 +314,15 @@ private int getSetpointEndTime() { private int getSetPointDefaultDuration() { // TODO : this informations could be sourced from Netatmo API instead of a local configuration element - return ((Number) config.get(SETPOINT_DEFAULT_DURATION)).intValue(); + Configuration conf = config; + Object defaultDuration = conf != null ? conf.get(SETPOINT_DEFAULT_DURATION) : null; + if (defaultDuration instanceof BigDecimal) { + return ((BigDecimal) defaultDuration).intValue(); + } + return 60; + } + + private Optional getApi() { + return getBridgeHandler().flatMap(handler -> handler.getThermostatApi()); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeCameraHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeCameraHandler.java index 4b2a22d095d42..87139de1eabfc 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeCameraHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeCameraHandler.java @@ -14,7 +14,7 @@ import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.types.State; @@ -26,15 +26,15 @@ * @author Ing. Peter Weiss - Initial contribution * */ +@NonNullByDefault public class NAWelcomeCameraHandler extends CameraHandler { - public NAWelcomeCameraHandler(@NonNull Thing thing, final TimeZoneProvider timeZoneProvider) { + public NAWelcomeCameraHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { super(thing, timeZoneProvider); } - @SuppressWarnings("null") @Override - protected State getNAThingProperty(@NonNull String channelId) { + protected State getNAThingProperty(String channelId) { switch (channelId) { case CHANNEL_WELCOME_CAMERA_STATUS: return getStatusState(); diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandler.java index b37ee8134bc0c..ef406998abab9 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandler.java @@ -41,7 +41,6 @@ import io.swagger.client.model.NAWelcomeEvent; import io.swagger.client.model.NAWelcomeHome; -import io.swagger.client.model.NAWelcomeHomeData; import io.swagger.client.model.NAWelcomePlace; import io.swagger.client.model.NAWelcomeSnapshot; import io.swagger.client.model.NAWelcomeSubEvent; @@ -59,7 +58,7 @@ public class NAWelcomeHomeHandler extends NetatmoDeviceHandler { private int iPersons = -1; private int iUnknowns = -1; - private Optional lastEvent = Optional.empty(); + private @Nullable NAWelcomeEvent lastEvent; private boolean isNewLastEvent; private @Nullable Integer dataTimeStamp; @@ -68,38 +67,34 @@ public NAWelcomeHomeHandler(Thing thing, final TimeZoneProvider timeZoneProvider } @Override - protected @Nullable NAWelcomeHome updateReadings() { - @Nullable - NAWelcomeHome result = null; - NAWelcomeHomeData homeDataBody = getBridgeHandler().getWelcomeDataBody(getId()); - if (homeDataBody != null) { - // data time stamp is updated to now as WelcomeDataBody does not provide any information according to this - // need - dataTimeStamp = (int) (Calendar.getInstance().getTimeInMillis() / 1000); - result = homeDataBody.getHomes().stream().filter(device -> device.getId().equalsIgnoreCase(getId())) - .findFirst().orElse(null); - if (result != null) { - result.getCameras().forEach(camera -> childs.put(camera.getId(), camera)); - - // Check how many persons are at home - iPersons = 0; - iUnknowns = 0; - - logger.debug("welcome home '{}' calculate Persons at home count", getId()); - result.getPersons().forEach(person -> { - iPersons += person.getOutOfSight() ? 0 : 1; - if (person.getPseudo() != null) { - childs.put(person.getId(), person); - } else { - iUnknowns += person.getOutOfSight() ? 0 : 1; - } - }); + protected Optional updateReadings() { + Optional result = getBridgeHandler().flatMap(handler -> handler.getWelcomeDataBody(getId())) + .map(dataBody -> dataBody.getHomes().stream().filter(device -> device.getId().equalsIgnoreCase(getId())) + .findFirst().orElse(null)); + // data time stamp is updated to now as WelcomeDataBody does not provide any information according to this + // need + dataTimeStamp = (int) (Calendar.getInstance().getTimeInMillis() / 1000); + result.ifPresent(home -> { + home.getCameras().forEach(camera -> childs.put(camera.getId(), camera)); + + // Check how many persons are at home + iPersons = 0; + iUnknowns = 0; + + logger.debug("welcome home '{}' calculate Persons at home count", getId()); + home.getPersons().forEach(person -> { + iPersons += person.getOutOfSight() ? 0 : 1; + if (person.getPseudo() != null) { + childs.put(person.getId(), person); + } else { + iUnknowns += person.getOutOfSight() ? 0 : 1; + } + }); - Optional previousLastEvent = lastEvent; - lastEvent = result.getEvents().stream().max(Comparator.comparingInt(NAWelcomeEvent::getTime)); - isNewLastEvent = previousLastEvent.isPresent() && !previousLastEvent.equals(lastEvent); - } - } + NAWelcomeEvent previousLastEvent = lastEvent; + lastEvent = home.getEvents().stream().max(Comparator.comparingInt(NAWelcomeEvent::getTime)).orElse(null); + isNewLastEvent = previousLastEvent != null && !previousLastEvent.equals(lastEvent); + }); return result; } @@ -117,23 +112,21 @@ protected State getNAThingProperty(String channelId) { case CHANNEL_WELCOME_HOME_UNKNOWNCOUNT: return iUnknowns != -1 ? new DecimalType(iUnknowns) : UnDefType.UNDEF; case CHANNEL_WELCOME_EVENT_TYPE: - return lastEvent.map(e -> toStringType(e.getType())).orElse(UnDefType.UNDEF); + return getLastEvent().map(e -> toStringType(e.getType())).orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_EVENT_TIME: - return lastEvent.map(e -> toDateTimeType(e.getTime(), timeZoneProvider.getTimeZone())) + return getLastEvent().map(e -> toDateTimeType(e.getTime(), timeZoneProvider.getTimeZone())) .orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_EVENT_CAMERAID: - if (lastEvent.isPresent()) { - Optional camera = getBridgeHandler() - .findNAThing(lastEvent.get().getCameraId()); - return camera.map(c -> toStringType(c.getThing().getLabel())).orElse(UnDefType.UNDEF); + if (getLastEvent().isPresent()) { + return findNAThing(getLastEvent().get().getCameraId()) + .map(c -> toStringType(c.getThing().getLabel())).orElse(UnDefType.UNDEF); } else { return UnDefType.UNDEF; } case CHANNEL_WELCOME_EVENT_PERSONID: - if (lastEvent.isPresent()) { - Optional person = getBridgeHandler() - .findNAThing(lastEvent.get().getPersonId()); - return person.map(p -> toStringType(p.getThing().getLabel())).orElse(UnDefType.UNDEF); + if (getLastEvent().isPresent()) { + return findNAThing(getLastEvent().get().getPersonId()) + .map(p -> toStringType(p.getThing().getLabel())).orElse(UnDefType.UNDEF); } else { return UnDefType.UNDEF; } @@ -142,12 +135,12 @@ protected State getNAThingProperty(String channelId) { case CHANNEL_WELCOME_EVENT_SNAPSHOT_URL: return findSnapshotURL().map(ChannelTypeUtils::toStringType).orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_EVENT_VIDEO_URL: - if (lastEvent.isPresent() && lastEvent.get().getVideoId() != null) { - String cameraId = lastEvent.get().getCameraId(); - Optional thing = getBridgeHandler().findNAThing(cameraId); + if (getLastEvent().isPresent() && getLastEvent().get().getVideoId() != null) { + String cameraId = getLastEvent().get().getCameraId(); + Optional thing = findNAThing(cameraId); if (thing.isPresent()) { CameraHandler eventCamera = (CameraHandler) thing.get(); - Optional streamUrl = eventCamera.getStreamURL(lastEvent.get().getVideoId()); + Optional streamUrl = eventCamera.getStreamURL(getLastEvent().get().getVideoId()); if (streamUrl.isPresent()) { return new StringType(streamUrl.get()); } @@ -155,14 +148,14 @@ protected State getNAThingProperty(String channelId) { } return UnDefType.UNDEF; case CHANNEL_WELCOME_EVENT_VIDEOSTATUS: - return lastEvent.map(e -> toStringType(e.getVideoStatus())).orElse(UnDefType.UNDEF); + return getLastEvent().map(e -> toStringType(e.getVideoStatus())).orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_EVENT_ISARRIVAL: - return lastEvent.map(e -> toOnOffType(e.getIsArrival())).orElse(UnDefType.UNDEF); + return getLastEvent().map(e -> toOnOffType(e.getIsArrival())).orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_EVENT_MESSAGE: return findEventMessage().map(m -> (State) new StringType(m.replace("", "").replace("", ""))) .orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_EVENT_SUBTYPE: - return lastEvent.map(e -> toDecimalType(e.getSubType())).orElse(UnDefType.UNDEF); + return getLastEvent().map(e -> toDecimalType(e.getSubType())).orElse(UnDefType.UNDEF); } return super.getNAThingProperty(channelId); } @@ -171,7 +164,8 @@ protected State getNAThingProperty(String channelId) { protected void triggerChannelIfRequired(String channelId) { if (isNewLastEvent) { if (CHANNEL_CAMERA_EVENT.equals(channelId)) { - findDetectedObjectTypes(lastEvent).forEach(detectedType -> triggerChannel(channelId, detectedType)); + findDetectedObjectTypes(getLastEvent()) + .forEach(detectedType -> triggerChannel(channelId, detectedType)); } } super.triggerChannelIfRequired(channelId); @@ -201,14 +195,14 @@ private static Set findDetectedObjectTypes(Optional even } private Optional findEventMessage() { - if (lastEvent.isPresent()) { + if (getLastEvent().isPresent()) { @Nullable - String message = lastEvent.get().getMessage(); + String message = getLastEvent().get().getMessage(); if (message != null) { return Optional.of(message); } - return findFirstSubEvent(lastEvent).map(NAWelcomeSubEvent::getMessage); + return findFirstSubEvent(getLastEvent()).map(NAWelcomeSubEvent::getMessage); } return Optional.empty(); } @@ -219,11 +213,11 @@ private Optional findEventMessage() { * @return Url of the picture or null */ protected Optional findSnapshotURL() { - if (lastEvent.isPresent()) { + if (getLastEvent().isPresent()) { @Nullable - NAWelcomeSnapshot snapshot = lastEvent.get().getSnapshot(); + NAWelcomeSnapshot snapshot = getLastEvent().get().getSnapshot(); if (snapshot == null) { - snapshot = findFirstSubEvent(lastEvent).map(NAWelcomeSubEvent::getSnapshot).orElse(null); + snapshot = findFirstSubEvent(getLastEvent()).map(NAWelcomeSubEvent::getSnapshot).orElse(null); } if (snapshot != null && snapshot.getId() != null && snapshot.getKey() != null) { @@ -237,16 +231,21 @@ protected Optional findSnapshotURL() { } @Override - protected @Nullable Integer getDataTimestamp() { - return dataTimeStamp; + protected Optional getDataTimestamp() { + Integer timestamp = dataTimeStamp; + return timestamp != null ? Optional.of(timestamp) : Optional.empty(); } private State getPlaceInfo(Function infoGetFunction) { - return Optional.ofNullable(device).map(d -> toStringType(infoGetFunction.apply(d.getPlace()))) - .orElse(UnDefType.UNDEF); + return getDevice().map(d -> toStringType(infoGetFunction.apply(d.getPlace()))).orElse(UnDefType.UNDEF); } private static Optional findFirstSubEvent(Optional event) { return event.map(NAWelcomeEvent::getEventList).flatMap(subEvents -> subEvents.stream().findFirst()); } + + private Optional getLastEvent() { + NAWelcomeEvent evt = lastEvent; + return evt != null ? Optional.of(evt) : Optional.empty(); + } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomePersonHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomePersonHandler.java index dd7bbc53a8454..114fd3651f36d 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomePersonHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomePersonHandler.java @@ -16,8 +16,9 @@ import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; import java.util.List; +import java.util.Optional; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.OnOffType; @@ -27,7 +28,6 @@ import org.eclipse.smarthome.core.types.State; import org.eclipse.smarthome.core.types.UnDefType; import org.eclipse.smarthome.io.net.http.HttpUtil; -import org.openhab.binding.netatmo.internal.handler.NetatmoBridgeHandler; import org.openhab.binding.netatmo.internal.handler.NetatmoModuleHandler; import io.swagger.client.api.WelcomeApi; @@ -42,25 +42,20 @@ * @author Ing. Peter Weiss - Initial contribution * */ +@NonNullByDefault public class NAWelcomePersonHandler extends NetatmoModuleHandler { - private String avatarURL; - private NAWelcomeEvent lastEvent; + private @Nullable String avatarURL; + private @Nullable NAWelcomeEvent lastEvent; - public NAWelcomePersonHandler(@NonNull Thing thing, final TimeZoneProvider timeZoneProvider) { + public NAWelcomePersonHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { super(thing, timeZoneProvider); } - private @Nullable WelcomeApi getWelcomeApi() { - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - return bridgeHandler == null ? null : bridgeHandler.getWelcomeApi(); - } - @Override public void updateChannels(Object module) { if (isRefreshRequired()) { - WelcomeApi welcomeApi = getWelcomeApi(); - if (welcomeApi != null) { - NAWelcomeEventResponse eventResponse = welcomeApi.getlasteventof(getParentId(), getId(), 10); + getApi().ifPresent(api -> { + NAWelcomeEventResponse eventResponse = api.getlasteventof(getParentId(), getId(), 10); // Search the last event for this person List rawEventList = eventResponse.getBody().getEventsList(); @@ -70,7 +65,7 @@ public void updateChannels(Object module) { lastEvent = event; } }); - } + }); setRefreshRequired(false); } @@ -78,24 +73,26 @@ public void updateChannels(Object module) { } @Override - protected State getNAThingProperty(@NonNull String channelId) { - NAWelcomePerson module = this.module; + protected State getNAThingProperty(String channelId) { + NAWelcomeEvent lastEvt = lastEvent; switch (channelId) { case CHANNEL_WELCOME_PERSON_LASTSEEN: - return module != null ? toDateTimeType(module.getLastSeen(), timeZoneProvider.getTimeZone()) - : UnDefType.UNDEF; + return getModule().map(m -> toDateTimeType(m.getLastSeen(), timeZoneProvider.getTimeZone())) + .orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_PERSON_ATHOME: - return module != null ? module.getOutOfSight() ? OnOffType.OFF : OnOffType.ON : UnDefType.UNDEF; + return getModule() + .map(m -> m.getOutOfSight() != null ? toOnOffType(!m.getOutOfSight()) : UnDefType.UNDEF) + .orElse(UnDefType.UNDEF); case CHANNEL_WELCOME_PERSON_AVATAR_URL: return toStringType(getAvatarURL()); case CHANNEL_WELCOME_PERSON_AVATAR: return getAvatarURL() != null ? HttpUtil.downloadImage(getAvatarURL()) : UnDefType.UNDEF; case CHANNEL_WELCOME_PERSON_LASTMESSAGE: - return (lastEvent != null && lastEvent.getMessage() != null) - ? toStringType(lastEvent.getMessage().replace("", "").replace("", "")) + return (lastEvt != null && lastEvt.getMessage() != null) + ? toStringType(lastEvt.getMessage().replace("", "").replace("", "")) : UnDefType.UNDEF; case CHANNEL_WELCOME_PERSON_LASTTIME: - return lastEvent != null ? toDateTimeType(lastEvent.getTime(), timeZoneProvider.getTimeZone()) + return lastEvt != null ? toDateTimeType(lastEvt.getTime(), timeZoneProvider.getTimeZone()) : UnDefType.UNDEF; case CHANNEL_WELCOME_PERSON_LASTEVENT: return getLastEventURL() != null ? HttpUtil.downloadImage(getLastEventURL()) : UnDefType.UNDEF; @@ -105,21 +102,20 @@ protected State getNAThingProperty(@NonNull String channelId) { return super.getNAThingProperty(channelId); } - private String getLastEventURL() { - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - if (bridgeHandler != null && lastEvent != null && lastEvent.getSnapshot() != null) { - return bridgeHandler.getPictureUrl(lastEvent.getSnapshot().getId(), lastEvent.getSnapshot().getKey()); + private @Nullable String getLastEventURL() { + NAWelcomeEvent lastEvt = lastEvent; + if (getBridgeHandler().isPresent() && lastEvt != null && lastEvt.getSnapshot() != null) { + return getBridgeHandler().get().getPictureUrl(lastEvt.getSnapshot().getId(), + lastEvt.getSnapshot().getKey()); } return null; } - private String getAvatarURL() { - NetatmoBridgeHandler bridgeHandler = getBridgeHandler(); - NAWelcomePerson module = this.module; - if (bridgeHandler != null && avatarURL == null && module != null) { - NAWelcomeFace face = module.getFace(); + private @Nullable String getAvatarURL() { + if (getBridgeHandler().isPresent() && avatarURL == null && getModule().isPresent()) { + NAWelcomeFace face = getModule().get().getFace(); if (face != null) { - avatarURL = bridgeHandler.getPictureUrl(face.getId(), face.getKey()); + avatarURL = getBridgeHandler().get().getPictureUrl(face.getId(), face.getKey()); } } return avatarURL; @@ -128,15 +124,19 @@ private String getAvatarURL() { @Override public void handleCommand(ChannelUID channelUID, Command command) { super.handleCommand(channelUID, command); - WelcomeApi welcomeApi = getWelcomeApi(); - if (welcomeApi != null && (command instanceof OnOffType) - && (CHANNEL_WELCOME_PERSON_ATHOME.equalsIgnoreCase(channelUID.getId()))) { - if ((OnOffType) command == OnOffType.OFF) { - welcomeApi.setpersonsaway(getParentId(), getId()); - } else { - welcomeApi.setpersonshome(getParentId(), "[\"" + getId() + "\"]"); - } - invalidateParentCacheAndRefresh(); + if ((command instanceof OnOffType) && (CHANNEL_WELCOME_PERSON_ATHOME.equalsIgnoreCase(channelUID.getId()))) { + getApi().ifPresent(api -> { + if ((OnOffType) command == OnOffType.OFF) { + api.setpersonsaway(getParentId(), getId()); + } else { + api.setpersonshome(getParentId(), "[\"" + getId() + "\"]"); + } + invalidateParentCacheAndRefresh(); + }); } } + + private Optional getApi() { + return getBridgeHandler().flatMap(handler -> handler.getWelcomeApi()); + } } diff --git a/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandlerTest.java b/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandlerTest.java index d654c957b6723..becbf05df8a90 100644 --- a/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandlerTest.java +++ b/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandlerTest.java @@ -12,7 +12,12 @@ */ package org.openhab.binding.netatmo.internal.presence; -import io.swagger.client.model.NAWelcomeCamera; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.util.Optional; + import org.eclipse.jdt.annotation.NonNull; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.OnOffType; @@ -31,10 +36,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.openhab.binding.netatmo.internal.NetatmoBindingConstants; -import java.util.Optional; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import io.swagger.client.model.NAWelcomeCamera; /** * @author Sven Strohschein - Initial contribution @@ -63,74 +65,81 @@ public void before() { presenceCameraThing = new ThingImpl(new ThingTypeUID("netatmo", "NOC"), "1"); presenceCamera = new NAWelcomeCamera(); - cameraStatusChannelUID = new ChannelUID(presenceCameraThing.getUID(), NetatmoBindingConstants.CHANNEL_CAMERA_STATUS); - floodlightChannelUID = new ChannelUID(presenceCameraThing.getUID(), NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT); - floodlightAutoModeChannelUID = new ChannelUID(presenceCameraThing.getUID(), NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE); + cameraStatusChannelUID = new ChannelUID(presenceCameraThing.getUID(), + NetatmoBindingConstants.CHANNEL_CAMERA_STATUS); + floodlightChannelUID = new ChannelUID(presenceCameraThing.getUID(), + NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT); + floodlightAutoModeChannelUID = new ChannelUID(presenceCameraThing.getUID(), + NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE); handler = new NAPresenceCameraHandlerAccessible(presenceCameraThing, presenceCamera); } @Test - public void testHandleCommand_Switch_Surveillance_on() { + public void testHandleCommandSwitchSurveillanceOn() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(cameraStatusChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch on + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch on verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/changestatus?status=on"); } @Test - public void testHandleCommand_Switch_Surveillance_off() { + public void testHandleCommandSwitchSurveillanceOff() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(cameraStatusChannelUID, OnOffType.OFF); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch off + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch off verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/changestatus?status=off"); } @Test - public void testHandleCommand_Switch_Surveillance_unknown_command() { + public void testHandleCommandSwitchSurveillanceUnknownCommand() { presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(cameraStatusChannelUID, RefreshType.REFRESH); - verify(requestExecutorMock, never()).executeGETRequest(any()); //nothing should get executed on a refresh command + verify(requestExecutorMock, never()).executeGETRequest(any()); // nothing should get executed on a refresh + // command } @Test - public void testHandleCommand_Switch_Surveillance_without_VPN() { + public void testHandleCommandSwitchSurveillanceWithoutVPN() { handler.handleCommand(cameraStatusChannelUID, OnOffType.ON); - verify(requestExecutorMock, never()).executeGETRequest(any()); //nothing should get executed when no VPN address is set + verify(requestExecutorMock, never()).executeGETRequest(any()); // nothing should get executed when no VPN + // address is set } @Test - public void testHandleCommand_Switch_Floodlight_on() { + public void testHandleCommandSwitchFloodlightOn() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch on - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch on + verify(requestExecutorMock) + .executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); } @Test - public void testHandleCommand_Switch_Floodlight_off() { + public void testHandleCommandSwitchFloodlightOff() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.OFF); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch off - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch off + verify(requestExecutorMock).executeGETRequest( + DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); } @Test - public void testHandleCommand_Switch_Floodlight_off_with_AutoMode_on() { + public void testHandleCommandSwitchFloodlightOffWithAutoModeOn() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); @@ -139,25 +148,29 @@ public void testHandleCommand_Switch_Floodlight_off_with_AutoMode_on() { handler.handleCommand(floodlightChannelUID, OnOffType.OFF); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch off - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22auto%22%7D"); + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch off + verify(requestExecutorMock).executeGETRequest( + DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22auto%22%7D"); } @Test - public void testHandleCommand_Switch_Floodlight_on_address_changed() { + public void testHandleCommandSwitchFloodlightOnAddressChanged() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - //1.) execute ping + 2.) execute switch on + // 1.) execute ping + 2.) execute switch on verify(requestExecutorMock, times(2)).executeGETRequest(any()); - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); + verify(requestExecutorMock) + .executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); handler.handleCommand(floodlightChannelUID, OnOffType.OFF); - //1.) execute ping + 2.) execute switch on + 3.) execute switch off + // 1.) execute ping + 2.) execute switch on + 3.) execute switch off verify(requestExecutorMock, times(3)).executeGETRequest(any()); - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); + verify(requestExecutorMock) + .executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); + verify(requestExecutorMock).executeGETRequest( + DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); final String newDummyVPNURL = DUMMY_VPN_URL + "2"; final String newDummyLocalURL = DUMMY_LOCAL_URL + "2"; @@ -167,178 +180,191 @@ public void testHandleCommand_Switch_Floodlight_on_address_changed() { presenceCamera.setVpnUrl(newDummyVPNURL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - //1.) execute ping + 2.) execute switch on + 3.) execute switch off + 4.) execute ping + 5.) execute switch on + // 1.) execute ping + 2.) execute switch on + 3.) execute switch off + 4.) execute ping + 5.) execute switch on verify(requestExecutorMock, times(5)).executeGETRequest(any()); - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); - verify(requestExecutorMock).executeGETRequest(newDummyLocalURL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); + verify(requestExecutorMock) + .executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); + verify(requestExecutorMock).executeGETRequest( + DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); + verify(requestExecutorMock).executeGETRequest( + newDummyLocalURL + "/command/floodlight_set_config?config=%7B%22mode%22:%22on%22%7D"); } @Test - public void testHandleCommand_Switch_Floodlight_unknown_command() { + public void testHandleCommandSwitchFloodlightUnknownCommand() { presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, RefreshType.REFRESH); - verify(requestExecutorMock, never()).executeGETRequest(any()); //nothing should get executed on a refresh command + verify(requestExecutorMock, never()).executeGETRequest(any()); // nothing should get executed on a refresh + // command } @Test - public void testHandleCommand_Switch_FloodlightAutoMode_on() { + public void testHandleCommandSwitchFloodlightAutoModeOn() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightAutoModeChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch auto-mode on - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22auto%22%7D"); + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch + // auto-mode on + verify(requestExecutorMock).executeGETRequest( + DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22auto%22%7D"); } @Test - public void testHandleCommand_Switch_FloodlightAutoMode_off() { + public void testHandleCommandSwitchFloodlightAutoModeOff() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(DUMMY_PING_RESPONSE); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightAutoModeChannelUID, OnOffType.OFF); - verify(requestExecutorMock, times(2)).executeGETRequest(any()); //1.) execute ping + 2.) execute switch off - verify(requestExecutorMock).executeGETRequest(DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); + verify(requestExecutorMock, times(2)).executeGETRequest(any()); // 1.) execute ping + 2.) execute switch off + verify(requestExecutorMock).executeGETRequest( + DUMMY_LOCAL_URL + "/command/floodlight_set_config?config=%7B%22mode%22:%22off%22%7D"); } @Test - public void testHandleCommand_Switch_FloodlightAutoMode_unknown_command() { + public void testHandleCommandSwitchFloodlightAutoModeUnknownCommand() { presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightAutoModeChannelUID, RefreshType.REFRESH); - verify(requestExecutorMock, never()).executeGETRequest(any()); //nothing should get executed on a refresh command + verify(requestExecutorMock, never()).executeGETRequest(any()); // nothing should get executed on a refresh + // command } /** * The request "fails" because there is no response content of the ping command. */ @Test - public void testHandleCommand_Request_failed() { + public void testHandleCommandRequestFailed() { presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(1)).executeGETRequest(any()); //1.) execute ping + verify(requestExecutorMock, times(1)).executeGETRequest(any()); // 1.) execute ping } @Test - public void testHandleCommand_without_VPN() { + public void testHandleCommandWithoutVPN() { handler.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, never()).executeGETRequest(any()); //no executions because the VPN URL is still unknown + verify(requestExecutorMock, never()).executeGETRequest(any()); // no executions because the VPN URL is still + // unknown } @Test - public void testHandleCommand_Ping_failed_NULL_Response() { + public void testHandleCommandPingFailedNULLResponse() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(Optional.of("")); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(1)).executeGETRequest(any()); //1.) execute ping + verify(requestExecutorMock, times(1)).executeGETRequest(any()); // 1.) execute ping } @Test - public void testHandleCommand_Ping_failed_empty_Response() { + public void testHandleCommandPingFailedEmptyResponse() { when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(Optional.of("")); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(1)).executeGETRequest(any()); //1.) execute ping + verify(requestExecutorMock, times(1)).executeGETRequest(any()); // 1.) execute ping } @Test - public void testHandleCommand_Ping_failed_wrong_Response() { - when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")).thenReturn(Optional.of("{ \"message\": \"error\" }")); + public void testHandleCommandPingFailedWrongResponse() { + when(requestExecutorMock.executeGETRequest(DUMMY_VPN_URL + "/command/ping")) + .thenReturn(Optional.of("{ \"message\": \"error\" }")); presenceCamera.setVpnUrl(DUMMY_VPN_URL); handler.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, times(1)).executeGETRequest(any()); //1.) execute ping + verify(requestExecutorMock, times(1)).executeGETRequest(any()); // 1.) execute ping } @Test - public void testHandleCommand_Module_NULL() { - NAPresenceCameraHandler handlerWithoutModule = new NAPresenceCameraHandler(presenceCameraThing, timeZoneProviderMock); + public void testHandleCommandModuleNULL() { + NAPresenceCameraHandler handlerWithoutModule = new NAPresenceCameraHandler(presenceCameraThing, + timeZoneProviderMock); handlerWithoutModule.handleCommand(floodlightChannelUID, OnOffType.ON); - verify(requestExecutorMock, never()).executeGETRequest(any()); //no executions because the thing isn't initialized + verify(requestExecutorMock, never()).executeGETRequest(any()); // no executions because the thing isn't + // initialized } @Test - public void testGetNAThingProperty_Common_Channel() { + public void testGetNAThingPropertyCommonChannel() { assertEquals(OnOffType.OFF, handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_CAMERA_STATUS)); } @Test - public void testGetNAThingProperty_Floodlight_On() { + public void testGetNAThingPropertyFloodlightOn() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.ON); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightChannelUID.getId())); } @Test - public void testGetNAThingProperty_Floodlight_Off() { + public void testGetNAThingPropertyFloodlightOff() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.OFF); assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightChannelUID.getId())); } @Test - public void testGetNAThingProperty_Floodlight_Auto() { + public void testGetNAThingPropertyFloodlightAuto() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.AUTO); - //When the floodlight is set to auto-mode it is currently off. + // When the floodlight is set to auto-mode it is currently off. assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightChannelUID.getId())); } @Test - public void testGetNAThingProperty_Floodlight_without_LightModeState() { + public void testGetNAThingPropertyFloodlightWithoutLightModeState() { assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightChannelUID.getId())); } @Test - public void testGetNAThingProperty_Floodlight_Module_NULL() { - NAPresenceCameraHandler handlerWithoutModule = new NAPresenceCameraHandler(presenceCameraThing, timeZoneProviderMock); + public void testGetNAThingPropertyFloodlightModuleNULL() { + NAPresenceCameraHandler handlerWithoutModule = new NAPresenceCameraHandler(presenceCameraThing, + timeZoneProviderMock); assertEquals(UnDefType.UNDEF, handlerWithoutModule.getNAThingProperty(floodlightChannelUID.getId())); } @Test - public void testGetNAThingProperty_FloodlightAutoMode_Floodlight_Auto() { + public void testGetNAThingPropertyFloodlightAutoModeFloodlightAuto() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.AUTO); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); } @Test - public void testGetNAThingProperty_FloodlightAutoMode_Floodlight_On() { + public void testGetNAThingPropertyFloodlightAutoModeFloodlightOn() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.ON); - //When the floodlight is initially on (on starting the binding), there is no information about if the auto-mode + // When the floodlight is initially on (on starting the binding), there is no information about if the auto-mode // was set before. Therefore the auto-mode is detected as deactivated / off. assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); } @Test - public void testGetNAThingProperty_FloodlightAutoMode_Floodlight_Off() { + public void testGetNAThingPropertyFloodlightAutoModeFloodlightOff() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.ON); - //When the floodlight is initially off (on starting the binding), the auto-mode isn't set. + // When the floodlight is initially off (on starting the binding), the auto-mode isn't set. assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); } @Test - public void testGetNAThingProperty_Floodlight_Scenario_with_AutoMode() { + public void testGetNAThingPropertyFloodlightScenarioWithAutoMode() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.AUTO); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightChannelUID.getId())); - //The auto-mode was initially set, after that the floodlight was switched on by the user. + // The auto-mode was initially set, after that the floodlight was switched on by the user. // In this case the binding should still know that the auto-mode is/was set. presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.ON); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightChannelUID.getId())); - //After that the user switched off the floodlight. + // After that the user switched off the floodlight. // In this case the binding should still know that the auto-mode is/was set. presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.OFF); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); @@ -346,18 +372,18 @@ public void testGetNAThingProperty_Floodlight_Scenario_with_AutoMode() { } @Test - public void testGetNAThingProperty_Floodlight_Scenario_without_AutoMode() { + public void testGetNAThingPropertyFloodlightScenarioWithoutAutoMode() { presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.OFF); assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightChannelUID.getId())); - //The auto-mode wasn't set, after that the floodlight was switched on by the user. + // The auto-mode wasn't set, after that the floodlight was switched on by the user. // In this case the binding should still know that the auto-mode isn't/wasn't set. presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.ON); assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); assertEquals(OnOffType.ON, handler.getNAThingProperty(floodlightChannelUID.getId())); - //After that the user switched off the floodlight. + // After that the user switched off the floodlight. // In this case the binding should still know that the auto-mode isn't/wasn't set. presenceCamera.setLightModeStatus(NAWelcomeCamera.LightModeStatusEnum.OFF); assertEquals(OnOffType.OFF, handler.getNAThingProperty(floodlightAutoModeChannelUID.getId())); @@ -365,8 +391,9 @@ public void testGetNAThingProperty_Floodlight_Scenario_without_AutoMode() { } @Test - public void testGetNAThingProperty_FloodlightAutoMode_Module_NULL() { - NAPresenceCameraHandler handlerWithoutModule = new NAPresenceCameraHandler(presenceCameraThing, timeZoneProviderMock); + public void testGetNAThingPropertyFloodlightAutoModeModuleNULL() { + NAPresenceCameraHandler handlerWithoutModule = new NAPresenceCameraHandler(presenceCameraThing, + timeZoneProviderMock); assertEquals(UnDefType.UNDEF, handlerWithoutModule.getNAThingProperty(floodlightAutoModeChannelUID.getId())); } @@ -379,7 +406,7 @@ public void testGetStreamURL() { } @Test - public void testGetStreamURL_local() { + public void testGetStreamURLLocal() { presenceCamera.setVpnUrl(DUMMY_VPN_URL); presenceCamera.setIsLocal(true); @@ -389,7 +416,7 @@ public void testGetStreamURL_local() { } @Test - public void testGetStreamURL_not_local() { + public void testGetStreamURLNotLocal() { presenceCamera.setVpnUrl(DUMMY_VPN_URL); presenceCamera.setIsLocal(false); @@ -399,7 +426,7 @@ public void testGetStreamURL_not_local() { } @Test - public void testGetStreamURL_without_VPN() { + public void testGetStreamURLWithoutVPN() { Optional streamURL = handler.getStreamURL("dummyVideoId"); assertFalse(streamURL.isPresent()); } @@ -413,7 +440,7 @@ public void testGetLivePictureURLState() { } @Test - public void testGetLivePictureURLState_without_VPN() { + public void testGetLivePictureURLStateWithoutVPN() { State livePictureURLState = handler.getLivePictureURLState(); assertEquals(UnDefType.UNDEF, livePictureURLState); } @@ -427,7 +454,7 @@ public void testGetLiveStreamState() { } @Test - public void testGetLiveStreamState_without_VPN() { + public void testGetLiveStreamStateWithoutVPN() { State liveStreamState = handler.getLiveStreamState(); assertEquals(UnDefType.UNDEF, liveStreamState); } @@ -445,7 +472,7 @@ private class NAPresenceCameraHandlerAccessible extends NAPresenceCameraHandler private NAPresenceCameraHandlerAccessible(Thing thing, NAWelcomeCamera presenceCamera) { super(thing, timeZoneProviderMock); - module = presenceCamera; + setModule(presenceCamera); } @Override diff --git a/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandlerTest.java b/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandlerTest.java index 1ecd81ee5bd10..f6bc93e963857 100644 --- a/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandlerTest.java +++ b/bundles/org.openhab.binding.netatmo/src/test/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandlerTest.java @@ -12,10 +12,14 @@ */ package org.openhab.binding.netatmo.internal.welcome; -import io.swagger.client.model.NAWelcomeEvent; -import io.swagger.client.model.NAWelcomeHome; -import io.swagger.client.model.NAWelcomeHomeData; -import io.swagger.client.model.NAWelcomeSubEvent; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Optional; + import org.eclipse.jdt.annotation.NonNull; import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.StringType; @@ -32,11 +36,10 @@ import org.openhab.binding.netatmo.internal.handler.NetatmoBridgeHandler; import org.openhab.binding.netatmo.internal.webhook.NAWebhookCameraEvent; -import java.util.Arrays; -import java.util.Collections; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import io.swagger.client.model.NAWelcomeEvent; +import io.swagger.client.model.NAWelcomeHome; +import io.swagger.client.model.NAWelcomeHomeData; +import io.swagger.client.model.NAWelcomeSubEvent; /** * @author Sven Strohschein - Initial contribution @@ -60,31 +63,33 @@ public void before() { } @Test - public void testUpdateReadings_with_Events() { - NAWelcomeEvent event_1 = createEvent(1592661881, NAWebhookCameraEvent.EventTypeEnum.PERSON); - NAWelcomeEvent event_2 = createEvent(1592661882, NAWebhookCameraEvent.EventTypeEnum.MOVEMENT); + public void testUpdateReadingsWithEvents() { + NAWelcomeEvent event1 = createEvent(1592661881, NAWebhookCameraEvent.EventTypeEnum.PERSON); + NAWelcomeEvent event2 = createEvent(1592661882, NAWebhookCameraEvent.EventTypeEnum.MOVEMENT); NAWelcomeHome home = new NAWelcomeHome(); home.setId(DUMMY_HOME_ID); - home.setEvents(Arrays.asList(event_1, event_2)); + home.setEvents(Arrays.asList(event1, event2)); NAWelcomeHomeData homeData = new NAWelcomeHomeData(); homeData.setHomes(Collections.singletonList(home)); - when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(homeData); + when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(Optional.of(homeData)); handler.updateReadings(); - //the second (last) event is expected - assertEquals(new StringType("movement"), handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); + // the second (last) event is expected + assertEquals(new StringType("movement"), + handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); - home.setEvents(Arrays.asList(event_2, event_1)); - //the second (last) event is still expected (independent from the order of these are added) - assertEquals(new StringType("movement"), handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); + home.setEvents(Arrays.asList(event2, event1)); + // the second (last) event is still expected (independent from the order of these are added) + assertEquals(new StringType("movement"), + handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); } @Test - public void testUpdateReadings_with_1_Event() { + public void testUpdateReadingsWith1Event() { NAWelcomeEvent event = createEvent(1592661881, NAWebhookCameraEvent.EventTypeEnum.PERSON); NAWelcomeHome home = new NAWelcomeHome(); @@ -94,22 +99,23 @@ public void testUpdateReadings_with_1_Event() { NAWelcomeHomeData homeData = new NAWelcomeHomeData(); homeData.setHomes(Collections.singletonList(home)); - when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(homeData); + when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(Optional.of(homeData)); handler.updateReadings(); - assertEquals(new StringType("person"), handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); + assertEquals(new StringType("person"), + handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); } @Test - public void testUpdateReadings_no_Events() { + public void testUpdateReadingsNoEvents() { NAWelcomeHome home = new NAWelcomeHome(); home.setId(DUMMY_HOME_ID); NAWelcomeHomeData homeData = new NAWelcomeHomeData(); homeData.setHomes(Collections.singletonList(home)); - when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(homeData); + when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(Optional.of(homeData)); handler.updateReadings(); @@ -117,8 +123,10 @@ public void testUpdateReadings_no_Events() { } @Test - public void testUpdateReadings_empty_HomeData() { - when(bridgeHandlerMock.getWelcomeDataBody(any())).thenReturn(new NAWelcomeHomeData()); + public void testUpdateReadingsEmptyHomeData() { + NAWelcomeHomeData homeData = new NAWelcomeHomeData(); + + when(bridgeHandlerMock.getWelcomeDataBody(any())).thenReturn(Optional.of(homeData)); handler.updateReadings(); @@ -126,7 +134,7 @@ public void testUpdateReadings_empty_HomeData() { } @Test - public void testUpdateReadings_no_HomeData() { + public void testUpdateReadingsNoHomeData() { handler.updateReadings(); assertEquals(UnDefType.UNDEF, handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); @@ -134,51 +142,55 @@ public void testUpdateReadings_no_HomeData() { @Test public void testTriggerChannelIfRequired() { - NAWelcomeEvent event_1 = createPresenceEvent(1592661881, NAWelcomeSubEvent.TypeEnum.ANIMAL); - NAWelcomeEvent event_2 = createPresenceEvent(1592661882, NAWelcomeSubEvent.TypeEnum.HUMAN); - NAWelcomeEvent event_3 = createEvent(1592661883, NAWebhookCameraEvent.EventTypeEnum.MOVEMENT); + NAWelcomeEvent event1 = createPresenceEvent(1592661881, NAWelcomeSubEvent.TypeEnum.ANIMAL); + NAWelcomeEvent event2 = createPresenceEvent(1592661882, NAWelcomeSubEvent.TypeEnum.HUMAN); + NAWelcomeEvent event3 = createEvent(1592661883, NAWebhookCameraEvent.EventTypeEnum.MOVEMENT); NAWelcomeHome home = new NAWelcomeHome(); home.setId(DUMMY_HOME_ID); - home.setEvents(Collections.singletonList(event_1)); + home.setEvents(Collections.singletonList(event1)); NAWelcomeHomeData homeData = new NAWelcomeHomeData(); homeData.setHomes(Collections.singletonList(home)); - when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(homeData); + when(bridgeHandlerMock.getWelcomeDataBody(DUMMY_HOME_ID)).thenReturn(Optional.of(homeData)); handler.updateReadings(); handler.triggerChannelIfRequired(NetatmoBindingConstants.CHANNEL_CAMERA_EVENT); - //No triggered event is expected, because the binding is just started (with existing events). + // No triggered event is expected, because the binding is just started (with existing events). assertEquals(0, handler.getTriggerChannelCount()); - home.setEvents(Arrays.asList(event_1, event_2)); + home.setEvents(Arrays.asList(event1, event2)); handler.updateReadings(); handler.triggerChannelIfRequired(NetatmoBindingConstants.CHANNEL_CAMERA_EVENT); - //1 triggered event is expected, because there is 1 new event since binding start (outdoor / detected human). + // 1 triggered event is expected, because there is 1 new event since binding start (outdoor / detected human). assertEquals(1, handler.getTriggerChannelCount()); - assertEquals(new StringType("outdoor"), handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); + assertEquals(new StringType("outdoor"), + handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); - home.setEvents(Arrays.asList(event_1, event_2)); + home.setEvents(Arrays.asList(event1, event2)); handler.updateReadings(); handler.triggerChannelIfRequired(NetatmoBindingConstants.CHANNEL_CAMERA_EVENT); - //No new triggered event is expected, because there are still the same events as before the refresh. + // No new triggered event is expected, because there are still the same events as before the refresh. assertEquals(1, handler.getTriggerChannelCount()); - assertEquals(new StringType("outdoor"), handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); + assertEquals(new StringType("outdoor"), + handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); - home.setEvents(Arrays.asList(event_1, event_2, event_3)); + home.setEvents(Arrays.asList(event1, event2, event3)); handler.updateReadings(); handler.triggerChannelIfRequired(NetatmoBindingConstants.CHANNEL_CAMERA_EVENT); - //1 new triggered event is expected (2 in sum), because there is 1 new event since the last triggered event (movement after outdoor / detected human). + // 1 new triggered event is expected (2 in sum), because there is 1 new event since the last triggered event + // (movement after outdoor / detected human). assertEquals(2, handler.getTriggerChannelCount()); - assertEquals(new StringType("movement"), handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); + assertEquals(new StringType("movement"), + handler.getNAThingProperty(NetatmoBindingConstants.CHANNEL_WELCOME_EVENT_TYPE)); } private static NAWelcomeEvent createPresenceEvent(int eventTime, NAWelcomeSubEvent.TypeEnum detectedObjectType) { @@ -207,8 +219,8 @@ private NAWelcomeHomeHandlerAccessible(Thing thing) { } @Override - protected NetatmoBridgeHandler getBridgeHandler() { - return bridgeHandlerMock; + protected Optional getBridgeHandler() { + return Optional.of(bridgeHandlerMock); } @Override