diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/NetatmoBindingProvider.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/NetatmoBindingProvider.java index 6fee6bdff7b..82a997bed40 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/NetatmoBindingProvider.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/NetatmoBindingProvider.java @@ -10,6 +10,7 @@ import org.openhab.core.binding.BindingProvider; import org.openhab.binding.netatmo.internal.NetatmoMeasureType; +import org.openhab.binding.netatmo.internal.NetatmoScale; /** * This interface is implemented by classes that can provide mapping information @@ -19,6 +20,7 @@ * taken into account. * * @author Andreas Brenk + * @author Rob Nielsen * @since 1.4.0 */ public interface NetatmoBindingProvider extends BindingProvider { @@ -62,4 +64,13 @@ public interface NetatmoBindingProvider extends BindingProvider { */ String getModuleId(String itemName); + /** + * Returns the scale to use when querying the Netatmo measure of the given + * {@code itemName}. + * + * @param itemName + * @return the Netatmo scale of the Item identified by {@code itemName} if + * it has a Netatmo binding, null otherwise + */ + NetatmoScale getNetatmoScale(String itemName); } diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBinding.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBinding.java index 2bc3eec0834..15fe9b7f9ee 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBinding.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBinding.java @@ -12,9 +12,11 @@ import static org.openhab.binding.netatmo.internal.messages.MeasurementRequest.createKey; import java.math.BigDecimal; +import java.util.Calendar; import java.util.Collection; import java.util.Dictionary; import java.util.Enumeration; +import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -118,12 +120,17 @@ protected void execute() { } DeviceMeasureValueMap deviceMeasureValueMap = processMeasurements(oauthCredentials); + if (deviceMeasureValueMap == null) { + return; + } + for (final NetatmoBindingProvider provider : this.providers) { for (final String itemName : provider.getItemNames()) { final String deviceId = provider.getDeviceId(itemName); final String moduleId = provider.getModuleId(itemName); final NetatmoMeasureType measureType = provider .getMeasureType(itemName); + final NetatmoScale scale = provider.getNetatmoScale(itemName); State state = null; switch (measureType) { @@ -157,22 +164,60 @@ protected void execute() { case NOISE: case PRESSURE: case RAIN: - final String requestKey = createKey(deviceId, - moduleId); - BigDecimal value = deviceMeasureValueMap.get( - requestKey).get(measureType.getMeasure()); - // Protect that sometimes Netatmo returns null where - // numeric value is awaited (issue #1848) - if (value != null) { - if (measureType == NetatmoMeasureType.TEMPERATURE) { - value = unitSystem.convertTemp(value); - } else if (measureType == NetatmoMeasureType.RAIN) { - value = unitSystem.convertRain(value); - } else if (measureType == NetatmoMeasureType.PRESSURE) { - value = pressureUnit.convertPressure(value); - } + case MIN_TEMP: + case MAX_TEMP: + case MIN_HUM: + case MAX_HUM: + case MIN_PRESSURE: + case MAX_PRESSURE: + case MIN_NOISE: + case MAX_NOISE: + case MIN_CO2: + case MAX_CO2: + case SUM_RAIN: + { + BigDecimal value = getValue( + deviceMeasureValueMap, measureType, + createKey(deviceId, moduleId, scale)); + // Protect that sometimes Netatmo returns null where + // numeric value is awaited (issue #1848) + if (value != null) { + if (NetatmoMeasureType + .isTemperature(measureType)) { + value = unitSystem.convertTemp(value); + } else if (NetatmoMeasureType + .isRain(measureType)) { + value = unitSystem.convertRain(value); + } else if (NetatmoMeasureType + .isPressure(measureType)) { + value = pressureUnit.convertPressure(value); + } - state = new DecimalType(value); + state = new DecimalType(value); + } + } + break; + case DATE_MIN_TEMP: + case DATE_MAX_TEMP: + case DATE_MIN_HUM: + case DATE_MAX_HUM: + case DATE_MIN_PRESSURE: + case DATE_MAX_PRESSURE: + case DATE_MIN_NOISE: + case DATE_MAX_NOISE: + case DATE_MIN_CO2: + case DATE_MAX_CO2: + { + final BigDecimal value = getValue( + deviceMeasureValueMap, measureType, + createKey(deviceId, moduleId, scale)); + if (value != null) { + final Calendar calendar = GregorianCalendar + .getInstance(); + calendar.setTimeInMillis(value.longValue() * 1000); + + state = new DateTimeType(calendar); + } } break; case BATTERYVP: @@ -206,13 +251,16 @@ protected void execute() { for (Device device : oauthCredentials.deviceListResponse .getDevices()) { if (stationPosition == null) { + DecimalType altitude = DecimalType.ZERO; + if (device.getAltitude() != null) { + altitude = new DecimalType(Math.round(unitSystem. + convertAltitude(device.getAltitude()))); + } stationPosition = new PointType( new DecimalType( - device.getLatitude()), - new DecimalType(device - .getLongitude()), - new DecimalType(Math.round(unitSystem. - convertAltitude(device.getAltitude())))); + new BigDecimal(device.getLatitude()).setScale(6, BigDecimal.ROUND_HALF_UP)), + new DecimalType(new BigDecimal(device.getLongitude()).setScale(6, BigDecimal.ROUND_HALF_UP)), + altitude); } if (device.getId().equals(deviceId)) { switch (measureType) { @@ -253,6 +301,13 @@ protected void execute() { } } + private BigDecimal getValue(DeviceMeasureValueMap deviceMeasureValueMap, + final NetatmoMeasureType measureType, final String requestKey) { + Map map = deviceMeasureValueMap.get(requestKey); + + return map != null ? map.get(measureType.getMeasure()) : null; + } + static class DeviceMeasureValueMap extends HashMap> { @@ -276,14 +331,20 @@ private DeviceMeasureValueMap processMeasurements( if (response.isError()) { final NetatmoError error = response.getError(); - if (error.isAccessTokenExpired()) { + if (error.isAccessTokenExpired() || error.isTokenNotVaid()) { + logger.debug("Token is expired or is not valid, refreshing: code = {} message = {}", + error.getCode(), error.getMessage()); + oauthCredentials.refreshAccessToken(); execute(); + + return null; } else { + logger.error("Error sending measurement request: code = {} message = {}", + error.getCode(), error.getMessage()); + throw new NetatmoException(error.getMessage()); } - - break; // abort processing measurement requests } else { processMeasurementResponse(request, response, deviceMeasureValueMap); @@ -301,10 +362,16 @@ private void processDeviceList(OAuthCredentials oauthCredentials) { final NetatmoError error = oauthCredentials.deviceListResponse .getError(); - if (error.isAccessTokenExpired()) { + if (error.isAccessTokenExpired() || error.isTokenNotVaid()) { + logger.debug("Token is expired or is not valid, refreshing: code = {} message = {}", + error.getCode(), error.getMessage()); + oauthCredentials.refreshAccessToken(); execute(); } else { + logger.error("Error processing device list: code = {} message = {}", + error.getCode(), error.getMessage()); + throw new NetatmoException(error.getMessage()); } @@ -415,15 +482,9 @@ private Collection createMeasurementRequests() { for (final NetatmoBindingProvider provider : this.providers) { for (final String itemName : provider.getItemNames()) { - - final String userid = provider.getUserid(itemName); - final String deviceId = provider.getDeviceId(itemName); - final String moduleId = provider.getModuleId(itemName); final NetatmoMeasureType measureType = provider .getMeasureType(itemName); - final String requestKey = createKey(deviceId, moduleId); - switch (measureType) { case TEMPERATURE: case CO2: @@ -431,16 +492,30 @@ private Collection createMeasurementRequests() { case NOISE: case PRESSURE: case RAIN: - OAuthCredentials oauthCredentials = getOAuthCredentials(userid); - if (oauthCredentials != null) { - if (!requests.containsKey(requestKey)) { - requests.put(requestKey, new MeasurementRequest( - oauthCredentials.accessToken, deviceId, - moduleId)); - } - requests.get(requestKey).addMeasure(measureType); - break; - } + case MIN_TEMP: + case MAX_TEMP: + case MIN_HUM: + case MAX_HUM: + case MIN_PRESSURE: + case MAX_PRESSURE: + case MIN_NOISE: + case MAX_NOISE: + case MIN_CO2: + case MAX_CO2: + case SUM_RAIN: + case DATE_MIN_TEMP: + case DATE_MAX_TEMP: + case DATE_MIN_HUM: + case DATE_MAX_HUM: + case DATE_MIN_PRESSURE: + case DATE_MAX_PRESSURE: + case DATE_MIN_NOISE: + case DATE_MAX_NOISE: + case DATE_MIN_CO2: + case DATE_MAX_CO2: + final NetatmoScale scale = provider.getNetatmoScale(itemName); + addMeasurement(requests, provider, itemName, measureType, scale); + break; default: break; } @@ -450,12 +525,40 @@ private Collection createMeasurementRequests() { return requests.values(); } + private void addMeasurement(final Map requests, + final NetatmoBindingProvider provider, final String itemName, + final NetatmoMeasureType measureType, final NetatmoScale scale) { + + final String userid = provider.getUserid(itemName); + final OAuthCredentials oauthCredentials = getOAuthCredentials(userid); + + if (oauthCredentials != null) { + final String deviceId = provider.getDeviceId(itemName); + final String moduleId = provider.getModuleId(itemName); + final String requestKey = createKey(deviceId, moduleId, scale); + + if (!requests.containsKey(requestKey)) { + requests.put(requestKey, new MeasurementRequest( + oauthCredentials.accessToken, deviceId, + moduleId, scale)); + } + requests.get(requestKey).addMeasure(measureType); + } + } + private void processMeasurementResponse(final MeasurementRequest request, final MeasurementResponse response, DeviceMeasureValueMap deviceMeasureValueMap) { final List values = response.getBody().get(0).getValues() .get(0); - final Map valueMap = new HashMap(); + + Map valueMap = deviceMeasureValueMap.get(request.getKey()); + if (valueMap == null) { + valueMap = new HashMap(); + + deviceMeasureValueMap.put(request.getKey(), valueMap); + deviceMeasureValueMap.timeStamp = new DateTimeType(response.getTimeStamp()); + } int index = 0; for (final String measure : request.getMeasures()) { @@ -463,10 +566,6 @@ private void processMeasurementResponse(final MeasurementRequest request, valueMap.put(measure, value); index++; } - - deviceMeasureValueMap.put(request.getKey(), valueMap); - deviceMeasureValueMap.timeStamp = new DateTimeType( - response.getTimeStamp()); } /** @@ -639,6 +738,14 @@ public void refreshAccessToken() { final RefreshTokenResponse response = request.execute(); logger.debug("Response: {}", response); + if (response == null) { + throw new NetatmoException("Could not refresh access token! If you see " + + "'Fatal transport error: javax.net.ssl.SSLHandshakeException' " + + "above. You need to install the StartCom CA certificate and restart openHAB. " + + "See https://github.com/openhab/openhab/wiki/Netatmo-Binding#missing-certificate-authority " + + "for more information."); + } + this.accessToken = response.getAccessToken(); deviceListRequest = new DeviceListRequest(this.accessToken); diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoGenericBindingProvider.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoGenericBindingProvider.java index 6b43bb0a1df..e514064f8f7 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoGenericBindingProvider.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoGenericBindingProvider.java @@ -60,6 +60,7 @@ * @author Andreas Brenk * @author Thomas.Eichstaedt-Engelen * @author Gaël L'hopital + * @author Rob Nielsen * @since 1.4.0 */ public class NetatmoGenericBindingProvider extends @@ -133,6 +134,16 @@ public String getModuleId(final String itemName) { return config != null ? config.moduleId : null; } + /** + * {@inheritDoc} + */ + @Override + public NetatmoScale getNetatmoScale(String itemName) { + final NetatmoBindingConfig config = (NetatmoBindingConfig) this.bindingConfigs + .get(itemName); + return config != null ? config.netatmoScale : null; + } + /** * {@inheritDoc} */ @@ -147,27 +158,48 @@ public void processBindingConfiguration(final String context, final NetatmoBindingConfig config = new NetatmoBindingConfig(); final String[] configParts = bindingConfig.split("#"); + String measureTypeString; switch (configParts.length) { case 2: config.deviceId = configParts[0]; - config.measureType = NetatmoMeasureType.fromString(configParts[1]); + measureTypeString = configParts[1]; break; case 3: config.deviceId = configParts[0]; config.moduleId = configParts[1]; - config.measureType = NetatmoMeasureType.fromString(configParts[2]); + measureTypeString = configParts[2]; break; case 4: config.userid = configParts[0]; config.deviceId = configParts[1]; config.moduleId = configParts[2]; - config.measureType = NetatmoMeasureType.fromString(configParts[3]); + measureTypeString = configParts[3]; break; default: throw new BindingConfigParseException( "A Netatmo binding configuration must consist of two, three or four parts - please verify your *.items file"); } + /* + * use a ',' when including scale so that it does not break backwards + * compatibility with case 4 above. + */ + final String[] measureTypeParts = measureTypeString.split(","); + switch (measureTypeParts.length) { + case 1: + config.measureType = NetatmoMeasureType.fromString(measureTypeParts[0]); + config.netatmoScale = config.measureType.getDefaultScale(); + break; + case 2: + config.measureType = NetatmoMeasureType.fromString(measureTypeParts[0]); + config.netatmoScale = NetatmoScale.fromString(measureTypeParts[1]); + break; + default: + throw new BindingConfigParseException( + "The last part of the Netatmo binding configuration must be 'type' or 'type,scale'" + + " - please verify your *.items file"); + } + logger.debug("Adding binding: {}", config); addBindingConfig(item, config); @@ -179,6 +211,7 @@ private static class NetatmoBindingConfig implements BindingConfig { String deviceId; String moduleId; NetatmoMeasureType measureType; + NetatmoScale netatmoScale; @Override public String toString() { diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoMeasureType.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoMeasureType.java index af764d59fb9..60804e9de3e 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoMeasureType.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoMeasureType.java @@ -12,22 +12,40 @@ /** * @author Gaël L'hopital + * @author Rob Nielsen * @since 1.6.0 * * This enum holds all the different measures and states available to be * retrieved by the Netatmo binding */ public enum NetatmoMeasureType { - CO2("CO2"), TEMPERATURE("Temperature"), HUMIDITY("Humidity"), NOISE("Noise"), PRESSURE( - "Pressure"), RAIN("Rain"), WIFISTATUS("WifiStatus"), ALTITUDE( - "Altitude"), LATITUDE("Latitude"), LONGITUDE("Longitude"), RFSTATUS( - "RfStatus"), BATTERYVP("BatteryVp"), TIMESTAMP("TimeStamp"), MODULENAME( - "ModuleName"), STATIONNAME("StationName"), COORDINATE("Coordinate"); + CO2("CO2", NetatmoScale.MAX), TEMPERATURE("Temperature", NetatmoScale.MAX), + HUMIDITY("Humidity", NetatmoScale.MAX), NOISE("Noise", NetatmoScale.MAX), + PRESSURE("Pressure", NetatmoScale.MAX), RAIN("Rain", NetatmoScale.MAX), + WIFISTATUS("WifiStatus", NetatmoScale.MAX), ALTITUDE("Altitude",NetatmoScale.MAX), + LATITUDE("Latitude", NetatmoScale.MAX), LONGITUDE("Longitude", NetatmoScale.MAX), + RFSTATUS("RfStatus", NetatmoScale.MAX), BATTERYVP("BatteryVp", NetatmoScale.MAX), + TIMESTAMP("TimeStamp", NetatmoScale.MAX), MODULENAME("ModuleName",NetatmoScale.MAX), + STATIONNAME("StationName", NetatmoScale.MAX), COORDINATE("Coordinate", NetatmoScale.MAX), + MIN_TEMP("min_temp", NetatmoScale.ONE_DAY), MAX_TEMP("max_temp", NetatmoScale.ONE_DAY), + MIN_HUM("min_hum", NetatmoScale.ONE_DAY), MAX_HUM("max_hum", NetatmoScale.ONE_DAY), + MIN_PRESSURE("min_pressure", NetatmoScale.ONE_DAY), MAX_PRESSURE("max_pressure", NetatmoScale.ONE_DAY), + MIN_NOISE("min_noise", NetatmoScale.ONE_DAY), MAX_NOISE("max_noise", NetatmoScale.ONE_DAY), + MIN_CO2("min_co2", NetatmoScale.ONE_DAY), MAX_CO2("max_co2", NetatmoScale.ONE_DAY), + SUM_RAIN("sum_rain", NetatmoScale.ONE_DAY), DATE_MIN_TEMP("date_min_temp", NetatmoScale.ONE_DAY), + DATE_MAX_TEMP("date_max_temp", NetatmoScale.ONE_DAY), DATE_MIN_HUM("date_min_hum", NetatmoScale.ONE_DAY), + DATE_MAX_HUM("date_max_hum", NetatmoScale.ONE_DAY), DATE_MIN_PRESSURE("date_min_pressure", NetatmoScale.ONE_DAY), + DATE_MAX_PRESSURE("date_max_pressure", NetatmoScale.ONE_DAY), DATE_MIN_NOISE("date_min_noise", NetatmoScale.ONE_DAY), + DATE_MAX_NOISE("date_max_noise", NetatmoScale.ONE_DAY), DATE_MIN_CO2("date_min_co2", NetatmoScale.ONE_DAY), + DATE_MAX_CO2("date_max_co2", NetatmoScale.ONE_DAY); - String measure; + final String measure; - private NetatmoMeasureType(String measure) { + final NetatmoScale defaultScale; + + private NetatmoMeasureType(String measure, NetatmoScale defaultScale) { this.measure = measure; + this.defaultScale = defaultScale; } public String getMeasure() { @@ -44,4 +62,25 @@ public static NetatmoMeasureType fromString(String measure) { } throw new IllegalArgumentException("Invalid measure: " + measure); } + + public NetatmoScale getDefaultScale() { + return defaultScale; + } + + public static boolean isPressure(NetatmoMeasureType measureType) { + return measureType == NetatmoMeasureType.PRESSURE + || measureType == NetatmoMeasureType.MIN_PRESSURE + || measureType == NetatmoMeasureType.MAX_PRESSURE; + } + + public static boolean isRain(NetatmoMeasureType measureType) { + return measureType == NetatmoMeasureType.RAIN + || measureType == NetatmoMeasureType.SUM_RAIN; + } + + public static boolean isTemperature(NetatmoMeasureType measureType) { + return measureType == NetatmoMeasureType.TEMPERATURE + || measureType == NetatmoMeasureType.MIN_TEMP + || measureType == NetatmoMeasureType.MAX_TEMP; + } } diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoPressureUnit.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoPressureUnit.java index 2ddb18d2565..95e99e9f959 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoPressureUnit.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoPressureUnit.java @@ -23,9 +23,10 @@ public enum NetatmoPressureUnit { MBAR("mbar"), INHG("inHg"), MMHG("mmHg"); public static final NetatmoPressureUnit DEFAULT_PRESSURE_UNIT = NetatmoPressureUnit.MBAR; - private static final BigDecimal MBAR_TO_INHG = new BigDecimal(0.02952998751); - private static final BigDecimal MBAR_TO_MMHG = new BigDecimal(0.750061683); + private static final BigDecimal MBAR_TO_INHG = new BigDecimal("0.0295"); + + private static final BigDecimal MBAR_TO_MMHG = new BigDecimal("0.7500"); String pressureUnit; @@ -50,6 +51,16 @@ public static NetatmoPressureUnit fromString(String pressureUnit) { + pressureUnit); } + /** + * Convert to appropriate measurement. + * + * The Barometer is accurate to +-1 mbar or +- 0.03 inHg + * + * @param value + * pressure in mbars + * + * @return value in proper measurement + */ public BigDecimal convertPressure(BigDecimal value) { if (this == DEFAULT_PRESSURE_UNIT) { return value; diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoScale.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoScale.java new file mode 100644 index 00000000000..cf5e6d40171 --- /dev/null +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoScale.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2010-2015, openHAB.org and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.netatmo.internal; + +import org.apache.commons.lang.StringUtils; + +/** + * @author Rob Nielsen + * @since 1.8.0 + * + * This enum holds all the different scales for the Netatmo binding + * when using the Netatmo getMeasure api + */ +public enum NetatmoScale { + MAX("max"), THIRTY_MIN("30min"), ONE_HOUR("1hour"), THREE_HOURS("3hours"), + ONE_DAY("1day"), ONE_WEEK("1week"), ONE_MONTH("1month"); + + String scale; + + private NetatmoScale(String scale) { + this.scale = scale; + } + + public String getScale() { + return scale; + } + + public static NetatmoScale fromString(String scale) { + if (!StringUtils.isEmpty(scale)) { + for (NetatmoScale unitSystemType : NetatmoScale.values()) { + if (unitSystemType.getScale().equalsIgnoreCase(scale)) { + return unitSystemType; + } + } + } + throw new IllegalArgumentException("Invalid scale: " + scale); + } +} \ No newline at end of file diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoUnitSystem.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoUnitSystem.java index 8ffe4b23e49..22b1f37e779 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoUnitSystem.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoUnitSystem.java @@ -26,11 +26,11 @@ public enum NetatmoUnitSystem { private static final double METERS_TO_FEET = 3.2808399; - private static final BigDecimal MM_TO_INCHES = new BigDecimal(0.0393700787); + private static final BigDecimal MM_TO_INCHES = new BigDecimal("0.0394"); - private static final BigDecimal ONE_POINT_EIGHT = new BigDecimal(1.8); + private static final BigDecimal ONE_POINT_EIGHT = new BigDecimal("1.8"); - private static final BigDecimal THIRTY_TWO = new BigDecimal(32); + private static final BigDecimal THIRTY_TWO = new BigDecimal("32"); String unitSystem; @@ -53,6 +53,14 @@ public static NetatmoUnitSystem fromString(String unitSystem) { throw new IllegalArgumentException("Invalid unitSystem: " + unitSystem); } + /** + * Convert to appropriate measurement. + * + * @param value + * altitude in Meters + * + * @return value in the proper measurement + */ public double convertAltitude(double value) { if (this == DEFAULT_UNIT_SYSTEM) { return value; @@ -61,6 +69,17 @@ public double convertAltitude(double value) { return value * METERS_TO_FEET; } + /** + * Convert to appropriate measurement. + * + * The Rain gauge is accurate to 1 mm/h or 0.04 in/h, and the range starts + * at 0.2 mm/h or 0.01 in/h. + * + * @param value + * rain in Millimeters + * + * @return value in the proper measurement + */ public BigDecimal convertRain(BigDecimal value) { if (this == DEFAULT_UNIT_SYSTEM) { return value; @@ -68,7 +87,17 @@ public BigDecimal convertRain(BigDecimal value) { return value.multiply(MM_TO_INCHES); } - + + /** + * Convert to appropriate measurement. + * + * The Thermometer is accurate to +- 0.3°C or +- 0.54°F + * + * @param value + * temperature in Celsius + * + * @return value the in proper measurement + */ public BigDecimal convertTemp(BigDecimal value) { if (this == DEFAULT_UNIT_SYSTEM) { return value; diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/DeviceListRequest.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/DeviceListRequest.java index 85e441b7548..8a15f565c24 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/DeviceListRequest.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/DeviceListRequest.java @@ -14,6 +14,8 @@ import org.apache.commons.httpclient.URIException; import org.apache.commons.lang.builder.ToStringBuilder; import org.openhab.binding.netatmo.internal.NetatmoException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A devicelist request returns the list of devices owned by the user, and their @@ -28,6 +30,8 @@ public class DeviceListRequest extends AbstractRequest { private static final String RESOURCE_URL = API_BASE_URL + "devicelist"; + private static final Logger logger = LoggerFactory.getLogger(DeviceListRequest.class); + private final String accessToken; /** @@ -46,6 +50,9 @@ public DeviceListRequest(final String accessToken) { @Override public DeviceListResponse execute() { final String url = prepare(); + + logger.debug(url); + String json = null; try { diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/MeasurementRequest.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/MeasurementRequest.java index c43e6587112..817e5d05bac 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/MeasurementRequest.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/MeasurementRequest.java @@ -19,12 +19,16 @@ import org.apache.commons.lang.builder.ToStringBuilder; import org.openhab.binding.netatmo.internal.NetatmoException; import org.openhab.binding.netatmo.internal.NetatmoMeasureType; +import org.openhab.binding.netatmo.internal.NetatmoScale; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Queries the Netatmo API for the measures of a single device or module. * * @author Andreas Brenk * @author Gaël L'hopital + * @author Rob Nielsen * @since 1.4.0 * @see getmeasure */ @@ -32,6 +36,8 @@ public class MeasurementRequest extends AbstractRequest { private static final String RESOURCE_URL = API_BASE_URL + "getmeasure"; + private static final Logger logger = LoggerFactory.getLogger(MeasurementRequest.class); + /** * @param deviceId * mandatory, must not be null @@ -39,12 +45,13 @@ public class MeasurementRequest extends AbstractRequest { * optional, may be null * @return a unique key suitable to store a request in a map */ - public static String createKey(final String deviceId, final String moduleId) { + public static String createKey(final String deviceId, final String moduleId, final NetatmoScale scale) { + final String s = ":" + scale.getScale(); if (moduleId == null) { - return "device:" + deviceId; + return "device:" + deviceId + s; } else { - return "module:" + moduleId; + return "module:" + moduleId + s; } } @@ -54,10 +61,13 @@ public static String createKey(final String deviceId, final String moduleId) { private final String moduleId; + private final NetatmoScale scale; + private final SortedSet measures = new TreeSet(); /** - * Creates a request for the measurements of a device or module. + * Creates a request for the measurements of a device or module + * using the default scale. * * If you don't specify a moduleId you will retrieve the device's * measurements. If you do specify a moduleId you will retrieve the module's @@ -70,12 +80,33 @@ public static String createKey(final String deviceId, final String moduleId) { */ public MeasurementRequest(final String accessToken, final String deviceId, final String moduleId) { + this(accessToken, deviceId, moduleId, NetatmoScale.MAX); + } + + /** + * Creates a request for the measurements of a device or module + * using the scale specified. + * + * If you don't specify a moduleId you will retrieve the device's + * measurements. If you do specify a moduleId you will retrieve the module's + * measurements. + * + * @param accessToken + * @param deviceId + * @param moduleId + * optional, may be null + * @param scale + */ + public MeasurementRequest(final String accessToken, final String deviceId, + final String moduleId, final NetatmoScale scale) { assert accessToken != null : "accessToken must not be null!"; assert deviceId != null : "deviceId must not be null!"; + assert scale != null : "scale must not be null!"; this.accessToken = accessToken; this.deviceId = deviceId; this.moduleId = moduleId; + this.scale = scale; } /** @@ -90,6 +121,9 @@ public void addMeasure(final NetatmoMeasureType measureType) { @Override public MeasurementResponse execute() { final String url = buildQueryString(); + + logger.debug(url); + String json = null; try { @@ -109,7 +143,7 @@ public MeasurementResponse execute() { * @see #createKey(String, String) */ public String getKey() { - return createKey(this.deviceId, this.moduleId); + return createKey(this.deviceId, this.moduleId, this.scale); } public SortedSet getMeasures() { @@ -139,7 +173,7 @@ private String buildQueryString() { final StringBuilder urlBuilder = new StringBuilder(RESOURCE_URL); urlBuilder.append("?access_token="); urlBuilder.append(this.accessToken); - urlBuilder.append("&scale=max"); + urlBuilder.append("&scale=" + scale.getScale()); urlBuilder.append("&date_end=last"); urlBuilder.append("&device_id="); urlBuilder.append(this.deviceId); diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/NetatmoError.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/NetatmoError.java index b3b7b74f0d8..ba090a4f3be 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/NetatmoError.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/NetatmoError.java @@ -56,6 +56,10 @@ public String getMessage() { return this.message; } + public boolean isTokenNotVaid() { + return this.code == 2; + } + public boolean isAccessTokenExpired() { return this.code == 3; } diff --git a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/RefreshTokenRequest.java b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/RefreshTokenRequest.java index 15b9764c518..c3c87afd16d 100644 --- a/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/RefreshTokenRequest.java +++ b/bundles/binding/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/messages/RefreshTokenRequest.java @@ -54,6 +54,9 @@ public RefreshTokenResponse execute() { this.clientId, this.clientSecret); json = executeQuery(content); + if (json == null) { + return null; + } final RefreshTokenResponse response = JSON.readValue(json, RefreshTokenResponse.class);