added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.luftdateninfo-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-luftdateninfo" description="LuftdatenInfo Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.luftdateninfo/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link LuftdatenInfoBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class LuftdatenInfoBindingConstants {
private static final String BINDING_ID = "luftdateninfo";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_PARTICULATE = new ThingTypeUID(BINDING_ID, "particulate");
public static final ThingTypeUID THING_TYPE_CONDITIONS = new ThingTypeUID(BINDING_ID, "conditions");
public static final ThingTypeUID THING_TYPE_NOISE = new ThingTypeUID(BINDING_ID, "noise");
// List of all Channel ids
public static final String PM25_CHANNEL = "pm25";
public static final String PM100_CHANNEL = "pm100";
public static final String TEMPERATURE_CHANNEL = "temperature";
public static final String HUMIDITY_CHANNEL = "humidity";
public static final String PRESSURE_CHANNEL = "pressure";
public static final String PRESSURE_SEA_CHANNEL = "pressure-sea";
public static final String NOISE_EQ_CHANNEL = "noise-eq";
public static final String NOISE_MIN_CHANNEL = "noise-min";
public static final String NOISE_MAX_CHANNEL = "noise-max";
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link LuftdatenInfoConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class LuftdatenInfoConfiguration {
public int sensorid = -1;
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.handler.ConditionHandler;
import org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler;
import org.openhab.binding.luftdateninfo.internal.handler.NoiseHandler;
import org.openhab.binding.luftdateninfo.internal.handler.PMHandler;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link LuftdatenInfoHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.luftdateninfo", service = ThingHandlerFactory.class)
public class LuftdatenInfoHandlerFactory extends BaseThingHandlerFactory {
protected final Logger logger = LoggerFactory.getLogger(LuftdatenInfoHandlerFactory.class);
@Activate
public LuftdatenInfoHandlerFactory(final @Reference HttpClientFactory httpClientFactory) {
HTTPHandler.init(httpClientFactory.getCommonHttpClient());
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
if (thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_PARTICULATE)
|| thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_CONDITIONS)
|| thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_NOISE)) {
return true;
} else {
return false;
}
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
if (thing.getThingTypeUID().equals(LuftdatenInfoBindingConstants.THING_TYPE_PARTICULATE)) {
return new PMHandler(thing);
} else if (thing.getThingTypeUID().equals(LuftdatenInfoBindingConstants.THING_TYPE_CONDITIONS)) {
return new ConditionHandler(thing);
} else if (thing.getThingTypeUID().equals(LuftdatenInfoBindingConstants.THING_TYPE_NOISE)) {
return new NoiseHandler(thing);
}
logger.info("Handler for {} not found", thing.getThingTypeUID());
return null;
}
}

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.dto;
import com.google.gson.annotations.SerializedName;
/**
* The {@link LuftdatenInfo} class definition for Logging identification
*
* @author Bernd Weymann - Initial contribution
*/
public class Location {
private int id;
private String country;
private String altitude;
private String latitude;
private String longitude;
private int indoor;
@SerializedName("exact_location")
private int exactLocation;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getAltitude() {
return altitude;
}
public void setAltitude(String altitude) {
this.altitude = altitude;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public Integer getIndoor() {
return indoor;
}
public void setIndoor(int indoor) {
this.indoor = indoor;
}
public int getExactLocation() {
return exactLocation;
}
public void setExactLocation(int exactLocation) {
this.exactLocation = exactLocation;
}
}

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.dto;
import com.google.gson.annotations.SerializedName;
/**
* The {@link Sensor} Data Transfer Object
*
* @author Bernd Weymann - Initial contribution
*/
public class Sensor {
private int id;
private String pin;
@SerializedName("sensor_type")
private SensorType sensorType;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
public SensorType getSensoTypee() {
return sensorType;
}
public void setSensorType(SensorType sensorType) {
this.sensorType = sensorType;
}
}

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.dto;
import java.util.List;
import com.google.gson.annotations.SerializedName;
/**
* The {@link SensorData} Data Transfer Object
*
* @author Bernd Weymann - Initial contribution
*/
public class SensorData {
private long id;
private String timestamp;
@SerializedName("sampling_rate")
private int samplingRate;
@SerializedName("sensordatavalues")
private List<SensorDataValue> sensorDataValues;
private Location location;
private Sensor sensor;
@Override
public String toString() {
return id + timestamp;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTimeStamp() {
return timestamp;
}
public void setTimeStamp(String timeStamp) {
this.timestamp = timeStamp;
}
public int getSamplingRate() {
return samplingRate;
}
public void setSamplingRate(int samplingRate) {
this.samplingRate = samplingRate;
}
public List<SensorDataValue> getSensorDataValues() {
return sensorDataValues;
}
public void setSensorDataValues(List<SensorDataValue> sensorDataValues) {
this.sensorDataValues = sensorDataValues;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public Sensor getSensor() {
return sensor;
}
public void setSensor(Sensor sensor) {
this.sensor = sensor;
}
}

View File

@@ -0,0 +1,56 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.dto;
import com.google.gson.annotations.SerializedName;
/**
* The {@link SensorDataValue} Data Transfer Object
*
* @author Bernd Weymann - Initial contribution
*/
public class SensorDataValue {
private long id;
@SerializedName("value_type")
private String valueType;
private String value;
@Override
public String toString() {
return valueType + ":" + value;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getValueType() {
return valueType;
}
public void setValueType(String valueType) {
this.valueType = valueType;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.dto;
/**
* The {@link SensorType} Data Transfer Object
*
* @author Bernd Weymann - Initial contribution
*/
public class SensorType {
private int id;
private String manufacturer;
private String name;
public Integer getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -0,0 +1,212 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.handler;
import java.time.LocalDateTime;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.LuftdatenInfoConfiguration;
import org.openhab.binding.luftdateninfo.internal.utils.DateTimeUtils;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link PMHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public abstract class BaseSensorHandler extends BaseThingHandler {
private static final LuftdatenInfoConfiguration DEFAULT_CONFIG = new LuftdatenInfoConfiguration();
private static final String EMPTY = "";
protected static final int REFRESH_INTERVAL_MIN = 5;
protected final Logger logger = LoggerFactory.getLogger(BaseSensorHandler.class);
protected LuftdatenInfoConfiguration config = DEFAULT_CONFIG;
protected ConfigStatus configStatus = ConfigStatus.UNKNOWN;
protected ThingStatus myThingStatus = ThingStatus.UNKNOWN;
protected UpdateStatus lastUpdateStatus = UpdateStatus.UNKNOWN;
protected @Nullable ScheduledFuture<?> refreshJob;
public enum ConfigStatus {
OK,
IS_NULL,
SENSOR_IS_NULL,
SENSOR_ID_NEGATIVE,
UNKNOWN
};
public enum UpdateStatus {
OK,
CONNECTION_ERROR,
CONNECTION_EXCEPTION,
VALUE_ERROR,
VALUE_EMPTY,
UNKNOWN
}
protected LifecycleStatus lifecycleStatus = LifecycleStatus.UNKNOWN;
public enum LifecycleStatus {
UNKNOWN,
RUNNING,
INITIALIZING,
DISPOSED
}
public BaseSensorHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
updateFromCache();
}
}
@Override
public void initialize() {
lifecycleStatus = LifecycleStatus.INITIALIZING;
scheduler.execute(this::startUp);
}
private void startUp() {
config = getConfigAs(LuftdatenInfoConfiguration.class);
configStatus = checkConfig(config);
if (configStatus == ConfigStatus.OK) {
// start getting values
dataUpdate();
} else {
// config error, no further actions triggered - Thing Status visible in UI
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Configuration not valid. Sensor ID as a number is mandatory!");
}
lifecycleStatus = LifecycleStatus.RUNNING;
}
private void startSchedule() {
ScheduledFuture<?> localRefreshJob = refreshJob;
if (localRefreshJob != null) {
if (localRefreshJob.isCancelled()) {
refreshJob = scheduler.scheduleWithFixedDelay(this::dataUpdate, 5, REFRESH_INTERVAL_MIN,
TimeUnit.MINUTES);
} // else - scheduler is already running!
} else {
refreshJob = scheduler.scheduleWithFixedDelay(this::dataUpdate, 5, REFRESH_INTERVAL_MIN, TimeUnit.MINUTES);
}
}
@Override
public void dispose() {
ScheduledFuture<?> localRefreshJob = refreshJob;
if (localRefreshJob != null) {
localRefreshJob.cancel(true);
}
lifecycleStatus = LifecycleStatus.DISPOSED;
}
/**
* Checks if config is valid - a) not null and b) sensorid is a number
*
* @param c
* @return
*/
private ConfigStatus checkConfig(@Nullable LuftdatenInfoConfiguration c) {
if (c != null) {
if (c.sensorid >= 0) {
return ConfigStatus.OK;
} else {
return ConfigStatus.SENSOR_ID_NEGATIVE;
}
} else {
return ConfigStatus.IS_NULL;
}
}
public LifecycleStatus getLifecycleStatus() {
return lifecycleStatus;
}
protected void dataUpdate() {
HTTPHandler.getHandler().request(config.sensorid, this);
}
public void onResponse(String data) {
lastUpdateStatus = updateChannels(data);
statusUpdate(lastUpdateStatus, EMPTY);
}
public void onError(String errorReason) {
statusUpdate(UpdateStatus.CONNECTION_EXCEPTION,
errorReason + " / " + LocalDateTime.now().format(DateTimeUtils.DTF));
}
protected void statusUpdate(UpdateStatus updateStatus, String details) {
if (updateStatus == UpdateStatus.OK) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
startSchedule();
} else {
switch (updateStatus) {
case CONNECTION_ERROR:
// start job even first update delivers no data - recovery is possible
startSchedule();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Update failed due to Connection error. Trying to recover in next refresh");
break;
case CONNECTION_EXCEPTION:
// start job even first update delivers a Connection Exception - recovery is possible
startSchedule();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, details);
break;
case VALUE_EMPTY:
// start job even if first update delivers no values - recovery possible
startSchedule();
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE,
"No values delivered by Sensor. Trying to recover in next refresh");
break;
case VALUE_ERROR:
// final status - values from sensor are wrong and manual check is needed
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Sensor values doesn't match - please check if Sensor ID is delivering the correct Thing channel values");
break;
default:
// final status - Configuration is wrong
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Error during update - please check your config data");
break;
}
}
}
@Override
protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
myThingStatus = status;
super.updateStatus(status, statusDetail, description);
}
protected abstract UpdateStatus updateChannels(@Nullable String json);
protected abstract void updateFromCache();
}

View File

@@ -0,0 +1,93 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.handler;
import static org.openhab.binding.luftdateninfo.internal.LuftdatenInfoBindingConstants.*;
import static org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler.*;
import java.util.List;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.utils.NumberUtils;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Thing;
/**
* The {@link ConditionHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class ConditionHandler extends BaseSensorHandler {
protected QuantityType<Temperature> temperatureCache = QuantityType.valueOf(-1, SIUnits.CELSIUS);
protected QuantityType<Dimensionless> humidityCache = QuantityType.valueOf(-1, SmartHomeUnits.PERCENT);
protected QuantityType<Pressure> pressureCache = QuantityType.valueOf(-1, SIUnits.PASCAL);
protected QuantityType<Pressure> pressureSeaCache = QuantityType.valueOf(-1, SIUnits.PASCAL);
public ConditionHandler(Thing thing) {
super(thing);
}
@Override
public UpdateStatus updateChannels(@Nullable String json) {
if (json != null) {
List<SensorDataValue> valueList = HTTPHandler.getHandler().getLatestValues(json);
if (valueList != null) {
if (HTTPHandler.getHandler().isCondition(valueList)) {
valueList.forEach(v -> {
if (v.getValueType().equals(TEMPERATURE)) {
temperatureCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SIUnits.CELSIUS);
updateState(TEMPERATURE_CHANNEL, temperatureCache);
} else if (v.getValueType().equals(HUMIDITY)) {
humidityCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SmartHomeUnits.PERCENT);
updateState(HUMIDITY_CHANNEL, humidityCache);
} else if (v.getValueType().equals(PRESSURE)) {
pressureCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), SIUnits.PASCAL);
updateState(PRESSURE_CHANNEL, pressureCache);
} else if (v.getValueType().equals(PRESSURE_SEALEVEL)) {
pressureSeaCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), SIUnits.PASCAL);
updateState(PRESSURE_SEA_CHANNEL, pressureSeaCache);
}
});
return UpdateStatus.OK;
} else {
return UpdateStatus.VALUE_ERROR;
}
} else {
return UpdateStatus.VALUE_EMPTY;
}
} else {
return UpdateStatus.CONNECTION_ERROR;
}
}
@Override
protected void updateFromCache() {
updateState(TEMPERATURE_CHANNEL, temperatureCache);
updateState(HUMIDITY_CHANNEL, humidityCache);
updateState(PRESSURE_CHANNEL, pressureCache);
updateState(PRESSURE_SEA_CHANNEL, pressureSeaCache);
}
}

View File

@@ -0,0 +1,164 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.handler;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.openhab.binding.luftdateninfo.internal.dto.SensorData;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.utils.DateTimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
* The {@link HTTPHandler} is responsible for HTTP requests and JSON handling
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class HTTPHandler {
private final Logger logger = LoggerFactory.getLogger(HTTPHandler.class);
private static final Gson GSON = new Gson();
private static final HTTPHandler HTTP_HANDLER = new HTTPHandler();
public static final String P1 = "P1";
public static final String P2 = "P2";
public static final String TEMPERATURE = "temperature";
public static final String HUMIDITY = "humidity";
public static final String PRESSURE = "pressure";
public static final String PRESSURE_SEALEVEL = "pressure_at_sealevel";
public static final String NOISE_EQ = "noise_LAeq";
public static final String NOISE_MIN = "noise_LA_min";
public static final String NOISE_MAX = "noise_LA_max";
private static String sensorUrl = "http://data.sensor.community/airrohr/v1/sensor/";
private static @Nullable HttpClient commonHttpClient;
public static void init(HttpClient httpClient) {
commonHttpClient = httpClient;
}
public static HTTPHandler getHandler() {
return HTTP_HANDLER;
}
public synchronized void request(int sensorId, BaseSensorHandler callback) {
HttpClient localClient = commonHttpClient;
if (localClient == null) {
logger.warn("HTTP Client not initialized");
} else {
String url = sensorUrl + sensorId + "/";
Request req = localClient.newRequest(url);
req.timeout(15, TimeUnit.SECONDS).send(new BufferingResponseListener() {
@NonNullByDefault({})
@Override
public void onComplete(org.eclipse.jetty.client.api.Result result) {
if (result.getResponse().getStatus() != 200) {
String failure;
if (result.getResponse().getReason() != null) {
failure = result.getResponse().getReason();
} else {
failure = result.getFailure().getMessage();
}
callback.onError(failure);
} else {
callback.onResponse(getContentAsString());
}
}
});
}
}
public @Nullable List<SensorDataValue> getLatestValues(String response) {
SensorData[] valueArray = GSON.fromJson(response, SensorData[].class);
if (valueArray.length == 0) {
return null;
} else if (valueArray.length == 1) {
SensorData v = valueArray[0];
return v.getSensorDataValues();
} else if (valueArray.length > 1) {
// declare first item as latest
SensorData latestData = valueArray[0];
String latestTimeStr = latestData.getTimeStamp();
LocalDateTime latestTime = DateTimeUtils.toDate(latestTimeStr);
if (latestTime == null) {
logDateConversionError(response, latestData);
}
for (int i = 1; i < valueArray.length; i++) {
SensorData iterData = valueArray[i];
String iterTimeStr = iterData.getTimeStamp();
LocalDateTime iterTime = DateTimeUtils.toDate(iterTimeStr);
if (iterTime == null) {
logDateConversionError(response, latestData);
}
if (iterTime != null && latestTime != null) {
if (latestTime.isBefore(iterTime)) {
// found item is newer - take it as latest
latestTime = iterTime;
latestData = iterData;
} // else - found item is older - nothing to do
} else {
logger.warn("One or two dates cannot be decoded 1) {} 2) {}", iterTimeStr, latestTimeStr);
}
}
return latestData.getSensorDataValues();
} else {
return null;
}
}
public void logDateConversionError(final String response, final Object dto) {
logger.warn("Unable to get timestamp");
logger.warn("Response: {}", response);
String json = GSON.toJson(dto);
logger.warn("GSon: {}", json);
}
public boolean isParticulate(@Nullable List<SensorDataValue> valueList) {
if (valueList == null) {
return false;
}
return valueList.stream().map(v -> v.getValueType()).filter(t -> t.equals(P1) || t.equals(P2)).findAny()
.isPresent();
}
public boolean isCondition(@Nullable List<SensorDataValue> valueList) {
if (valueList == null) {
return false;
}
return valueList.stream().map(v -> v.getValueType()).filter(
t -> t.equals(TEMPERATURE) || t.equals(HUMIDITY) || t.equals(PRESSURE) || t.equals(PRESSURE_SEALEVEL))
.findAny().isPresent();
}
public boolean isNoise(@Nullable List<SensorDataValue> valueList) {
if (valueList == null) {
return false;
}
return valueList.stream().map(v -> v.getValueType())
.filter(t -> t.equals(NOISE_EQ) || t.equals(NOISE_MAX) || t.equals(NOISE_MIN)).findAny().isPresent();
}
}

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.handler;
import static org.openhab.binding.luftdateninfo.internal.LuftdatenInfoBindingConstants.*;
import static org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler.*;
import java.util.List;
import javax.measure.quantity.Dimensionless;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.utils.NumberUtils;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Thing;
/**
* The {@link NoiseHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class NoiseHandler extends BaseSensorHandler {
protected QuantityType<Dimensionless> noiseEQCache = QuantityType.valueOf(-1, SmartHomeUnits.DECIBEL);
protected QuantityType<Dimensionless> noiseMinCache = QuantityType.valueOf(-1, SmartHomeUnits.DECIBEL);
protected QuantityType<Dimensionless> noiseMaxCache = QuantityType.valueOf(-1, SmartHomeUnits.DECIBEL);
public NoiseHandler(Thing thing) {
super(thing);
}
@Override
public UpdateStatus updateChannels(@Nullable String json) {
if (json != null) {
List<SensorDataValue> valueList = HTTPHandler.getHandler().getLatestValues(json);
if (valueList != null) {
if (HTTPHandler.getHandler().isNoise(valueList)) {
valueList.forEach(v -> {
if (v.getValueType().equals(NOISE_EQ)) {
noiseEQCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SmartHomeUnits.DECIBEL);
updateState(NOISE_EQ_CHANNEL, noiseEQCache);
} else if (v.getValueType().equals(NOISE_MIN)) {
noiseMinCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SmartHomeUnits.DECIBEL);
updateState(NOISE_MIN_CHANNEL, noiseMinCache);
} else if (v.getValueType().equals(NOISE_MAX)) {
noiseMaxCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SmartHomeUnits.DECIBEL);
updateState(NOISE_MAX_CHANNEL, noiseMaxCache);
}
});
return UpdateStatus.OK;
} else {
return UpdateStatus.VALUE_ERROR;
}
} else {
return UpdateStatus.VALUE_EMPTY;
}
} else {
return UpdateStatus.CONNECTION_ERROR;
}
}
@Override
protected void updateFromCache() {
updateState(NOISE_EQ_CHANNEL, noiseEQCache);
updateState(NOISE_MIN_CHANNEL, noiseMinCache);
updateState(NOISE_MAX_CHANNEL, noiseMaxCache);
}
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.handler;
import static org.openhab.binding.luftdateninfo.internal.LuftdatenInfoBindingConstants.*;
import static org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler.*;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.utils.NumberUtils;
import org.openhab.core.library.dimension.Density;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Thing;
/**
* The {@link PMHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class PMHandler extends BaseSensorHandler {
protected QuantityType<Density> pm25Cache = QuantityType.valueOf(-1, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE);
protected QuantityType<Density> pm100Cache = QuantityType.valueOf(-1, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE);
public PMHandler(Thing thing) {
super(thing);
}
@Override
public UpdateStatus updateChannels(@Nullable String json) {
if (json != null) {
List<SensorDataValue> valueList = HTTPHandler.getHandler().getLatestValues(json);
if (valueList != null) {
if (HTTPHandler.getHandler().isParticulate(valueList)) {
valueList.forEach(v -> {
if (v.getValueType().equals(P1)) {
pm100Cache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SmartHomeUnits.MICROGRAM_PER_CUBICMETRE);
updateState(PM100_CHANNEL, pm100Cache);
} else if (v.getValueType().equals(P2)) {
pm25Cache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SmartHomeUnits.MICROGRAM_PER_CUBICMETRE);
updateState(PM25_CHANNEL, pm25Cache);
}
});
return UpdateStatus.OK;
} else {
return UpdateStatus.VALUE_ERROR;
}
} else {
return UpdateStatus.VALUE_EMPTY;
}
} else {
return UpdateStatus.CONNECTION_ERROR;
}
}
@Override
protected void updateFromCache() {
updateState(PM25_CHANNEL, pm25Cache);
updateState(PM100_CHANNEL, pm100Cache);
}
}

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.utils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DateTimeUtils} class provides helpers for converting Dates and Times.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class DateTimeUtils {
public static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
private static final Logger LOGGER = LoggerFactory.getLogger(DateTimeUtils.class);
public static synchronized @Nullable LocalDateTime toDate(String dateTime) {
try {
return LocalDateTime.from(DTF.parse(dateTime));
} catch (DateTimeParseException e) {
LOGGER.debug("Unable to parse date {}", dateTime);
return null;
}
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.utils;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link NumberUtils} class provides helpers for converting Numbers.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class NumberUtils {
public static final double UNDEF = Double.NaN;
public static double round(Object o, int places) {
double value = convert(o);
// for negative places return plain number
if (places < 0) {
return value;
}
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
public static double convert(Object o) {
// ensure value not null
double value = UNDEF;
if (o instanceof Number) {
value = ((Number) o).doubleValue();
} else if (o instanceof String) {
value = Double.parseDouble(o.toString());
}
return value;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="luftdateninfo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>LuftdatenInfo Binding</name>
<description>Binding to integrate DIY Sensors from luftdaten.info Sensor Community</description>
<author>Bernd Weymann</author>
</binding:binding>

View File

@@ -0,0 +1,19 @@
binding.luftdateninfo.name = LuftdatenInfo Binding
binding.luftdateninfo.description = Das Binding stellt die Daten der Eigenbau-Sensoren von LuftdatenInfo zur Verfügung
thing-type.luftdateninfo.particulate.label = Feinstaubsensor
thing-type.luftdateninfo.particulate.description = Messung der Feinstaubbelastung in der Umgebung
thing-type.luftdateninfo.conditions.label = Umweltsensor
thing-type.luftdateninfo.conditions.description = Messung der Temperatur, Luftfeuchtigkeit und Luftdruck
thing-type.luftdateninfo.noise.label = Lärmsensor
thing-type.luftdateninfo.noise.description = Messung der Lärmbelastung in der Umgebung
channel-type.luftdateninfo.pm25-channel.label = Feinstaub der Kategorie PM 2.5
channel-type.luftdateninfo.pm100-channel.label = Feinstaub der Kategorie PM 10.0
channel-type.luftdateninfo.temp-channel.label = Temperatur
channel-type.luftdateninfo.hum-channel.label = Luftfeuchtigkeit
channel-type.luftdateninfo.pressure-channel.label = Atmosphärischer Druck
channel-type.luftdateninfo.pressure-sea-channel.label = Atmosphärischer Druck Auf Meereshöhe
channel-type.luftdateninfo.noise-eq-channel.label = Durchschnittlicher Lärmpegel
channel-type.luftdateninfo.noise-min-channel.label = Minimaler Lärmpegel
channel-type.luftdateninfo.noise-max-channel.label = Maximaler Lärmpegel

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="luftdateninfo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="particulate">
<label>Particulate Sensor</label>
<description>Sensor to measure Particulate Matter (PM)</description>
<channels>
<channel id="pm25" typeId="pm25-channel"/>
<channel id="pm100" typeId="pm100-channel"/>
</channels>
<config-description>
<parameter name="sensorid" type="integer" required="true">
<label>Sensor ID</label>
<description>Sensor ID</description>
</parameter>
</config-description>
</thing-type>
<thing-type id="conditions">
<label>Condition Sensor</label>
<description>Sensor to measure Temperature and Humidity conditions</description>
<channels>
<channel id="temperature" typeId="temp-channel"/>
<channel id="humidity" typeId="hum-channel"/>
<channel id="pressure" typeId="pressure-channel"/>
<channel id="pressure-sea" typeId="pressure-sea-channel"/>
</channels>
<config-description>
<parameter name="sensorid" type="integer" required="true">
<label>Sensor ID</label>
<description>Sensor ID</description>
</parameter>
</config-description>
</thing-type>
<thing-type id="noise">
<label>Noise Sensor</label>
<description>Sensor to measure noise on location</description>
<channels>
<channel id="noise-eq" typeId="noise-eq-channel"/>
<channel id="noise-min" typeId="noise-min-channel"/>
<channel id="noise-max" typeId="noise-max-channel"/>
</channels>
<config-description>
<parameter name="sensorid" type="integer" required="true">
<label>Sensor ID</label>
<description>Sensor ID</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="pm25-channel">
<item-type>Number:Density</item-type>
<label>Particulate Matter category 2.5</label>
</channel-type>
<channel-type id="pm100-channel">
<item-type>Number:Density</item-type>
<label>Particulate Matter category 10.0</label>
</channel-type>
<channel-type id="temp-channel">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Temperature from the selected Sensor ID</description>
</channel-type>
<channel-type id="hum-channel">
<item-type>Number:Dimensionless</item-type>
<label>Humidity</label>
<description>Humidity from the selected Sensor ID</description>
</channel-type>
<channel-type id="pressure-channel">
<item-type>Number:Pressure</item-type>
<label>Atmospheric Pressure</label>
<description>Atmospheric Pressure from the selected Sensor ID</description>
</channel-type>
<channel-type id="pressure-sea-channel">
<item-type>Number:Pressure</item-type>
<label>Atmospheric Pressure Sea Level</label>
<description>Atmospheric Pressure at sea level from the selected Sensor ID</description>
</channel-type>
<channel-type id="noise-eq-channel">
<item-type>Number:Dimensionless</item-type>
<label>Average Noise</label>
<description>Average noise level from the selected Sensor ID</description>
</channel-type>
<channel-type id="noise-min-channel">
<item-type>Number:Dimensionless</item-type>
<label>Minimum Noise</label>
<description>Minimum noise level (last 2.5 minutes) from the selected Sensor ID</description>
</channel-type>
<channel-type id="noise-max-channel">
<item-type>Number:Dimensionless</item-type>
<label>Maximum Noise</label>
<description>Maximum noise level (last 2.5 minutes) from the selected Sensor ID</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,129 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.*;
import java.util.HashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.handler.BaseSensorHandler.UpdateStatus;
import org.openhab.binding.luftdateninfo.internal.mock.ConditionHandlerExtension;
import org.openhab.binding.luftdateninfo.internal.mock.ThingMock;
import org.openhab.binding.luftdateninfo.internal.util.FileReader;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
/**
* The {@link ConditionHandlerTest} Test Condition Handler updates
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class ConditionHandlerTest {
@Test
public void testValidNoPressureUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
ConditionHandlerExtension condHandler = new ConditionHandlerExtension(t);
String pmJson = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
if (pmJson != null) {
UpdateStatus result = condHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.OK, result);
assertEquals("Temperature", QuantityType.valueOf(22.7, SIUnits.CELSIUS), condHandler.getTemperature());
assertEquals("Humidity", QuantityType.valueOf(61.0, SmartHomeUnits.PERCENT), condHandler.getHumidity());
assertEquals("Pressure", QuantityType.valueOf(-1, SIUnits.PASCAL), condHandler.getPressure());
assertEquals("Pressure Sea", QuantityType.valueOf(-1, SIUnits.PASCAL), condHandler.getPressureSea());
} else {
assertTrue(false);
}
}
@Test
public void testValidWithPressureUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
ConditionHandlerExtension condHandler = new ConditionHandlerExtension(t);
String pmJson = FileReader.readFileInString("src/test/resources/condition-result-plus-pressure.json");
if (pmJson != null) {
UpdateStatus result = condHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.OK, result);
assertEquals("Temperature", QuantityType.valueOf(21.5, SIUnits.CELSIUS), condHandler.getTemperature());
assertEquals("Humidity", QuantityType.valueOf(58.5, SmartHomeUnits.PERCENT), condHandler.getHumidity());
assertEquals("Pressure", QuantityType.valueOf(100200.0, SIUnits.PASCAL), condHandler.getPressure());
assertEquals("Pressure Sea", QuantityType.valueOf(101968.7, SIUnits.PASCAL), condHandler.getPressureSea());
} else {
assertTrue(false);
}
}
@Test
public void testInvalidUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
ConditionHandlerExtension condHandler = new ConditionHandlerExtension(t);
String pmJson = FileReader.readFileInString("src/test/resources/noise-result.json");
if (pmJson != null) {
UpdateStatus result = condHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.VALUE_ERROR, result);
} else {
assertTrue(false);
}
}
@Test
public void testEmptyUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
ConditionHandlerExtension condHandler = new ConditionHandlerExtension(t);
UpdateStatus result = condHandler.updateChannels("[]");
assertEquals("Valid update", UpdateStatus.VALUE_EMPTY, result);
}
@Test
public void testNullUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
ConditionHandlerExtension condHandler = new ConditionHandlerExtension(t);
UpdateStatus result = condHandler.updateChannels(null);
assertEquals("Valid update", UpdateStatus.CONNECTION_ERROR, result);
}
}

View File

@@ -0,0 +1,84 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.*;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.dto.SensorData;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler;
import org.openhab.binding.luftdateninfo.internal.util.FileReader;
import com.google.gson.Gson;
/**
* The {@link DTOTest} Data Transfer Object - test conversions
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class DTOTest {
@Test
public void testConditions() {
String result = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
Gson gson = new Gson();
SensorData[] valueArray = gson.fromJson(result, SensorData[].class);
// System.out.println(valueArray.length);
assertEquals("Array size", 2, valueArray.length);
SensorData d = valueArray[0];
// Assure latest data is taken
String dateStr = d.getTimeStamp();
if (dateStr.equals("2020-06-09 06:38:08")) {
// take newer one
d = valueArray[1];
}
List<SensorDataValue> sensorDataVaueList = d.getSensorDataValues();
assertNotNull(d);
sensorDataVaueList.forEach(v -> {
if (v.getValueType().equals(HTTPHandler.TEMPERATURE)) {
assertEquals("Temperature", "22.70", v.getValue());
} else if (v.getValueType().equals(HTTPHandler.HUMIDITY)) {
assertEquals("Humidity", "61.00", v.getValue());
}
});
}
@Test
public void testDecoding() {
String result = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
Gson gson = new Gson();
SensorData[] valueArray = gson.fromJson(result, SensorData[].class);
// System.out.println(valueArray.length);
assertEquals("Array size", 2, valueArray.length);
SensorData d = valueArray[0];
// Assure latest data is taken
String dateStr = d.getTimeStamp();
if (dateStr.equals("2020-06-09 06:38:08")) {
// take newer one
d = valueArray[1];
}
// test decoding a small part
String json = gson.toJson(d);
// System.out.println(json);
// check if correct timestamp is included
assertTrue(json.contains("\"timestamp\":\"2020-06-09 06:40:34\""));
}
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.*;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler;
import org.openhab.binding.luftdateninfo.internal.util.FileReader;
/**
* The {@link HTTPHandlerEvalTest} test all evaluations on SensorDataValues
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class HTTPHandlerEvalTest {
private @Nullable List<SensorDataValue> conditions;
private @Nullable List<SensorDataValue> particulate;
private @Nullable List<SensorDataValue> noise;
private HTTPHandler http = new HTTPHandler();
@Before
public void setUp() {
String conditionsStr = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
assertNotNull(conditionsStr);
conditions = http.getLatestValues(conditionsStr);
String particulateStr = FileReader.readFileInString("src/test/resources/pm-result.json");
assertNotNull(particulateStr);
particulate = http.getLatestValues(particulateStr);
String noiseStr = FileReader.readFileInString("src/test/resources/noise-result.json");
assertNotNull(noiseStr);
noise = http.getLatestValues(noiseStr);
}
@Test
public void testIsCondition() {
assertTrue(http.isCondition(conditions));
assertFalse(http.isCondition(particulate));
assertFalse(http.isCondition(noise));
assertFalse(http.isCondition(null));
}
@Test
public void testIsParticulate() {
assertFalse(http.isParticulate(conditions));
assertTrue(http.isParticulate(particulate));
assertFalse(http.isParticulate(noise));
assertFalse(http.isParticulate(null));
}
@Test
public void testIsNoise() {
assertFalse(http.isNoise(conditions));
assertFalse(http.isNoise(particulate));
assertTrue(http.isNoise(noise));
assertFalse(http.isNoise(null));
}
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.*;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.dto.SensorDataValue;
import org.openhab.binding.luftdateninfo.internal.handler.HTTPHandler;
import org.openhab.binding.luftdateninfo.internal.util.FileReader;
/**
* The {@link HTTPHandlerValueTest} test values decoding of HTTPHandler
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class HTTPHandlerValueTest {
private HTTPHandler http = new HTTPHandler();
/**
* test if really the latest values are returned
* resource1 is json with ordering according to time while resource2 the entries flipped
*/
@Test
public void testValueDecoding() {
String resource1 = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
assertNotNull(resource1);
List<SensorDataValue> l = http.getLatestValues(resource1);
assertNotNull(l);
l.forEach(sd -> {
testSensorValue(sd);
});
String resource2 = FileReader
.readFileInString("src/test/resources/condition-result-no-pressure-flipped-values.json");
assertNotNull(resource2);
l = http.getLatestValues(resource2);
assertNotNull(l);
l.forEach(sd -> {
testSensorValue(sd);
});
}
private void testSensorValue(SensorDataValue s) {
if (s.getValueType().equals(HTTPHandler.TEMPERATURE)) {
assertEquals("Temperature resource 1", "22.70", s.getValue());
} else if (s.getValueType().equals(HTTPHandler.HUMIDITY)) {
assertEquals("Humidity resource 1", "61.00", s.getValue());
} else {
assertTrue(false);
}
// System.out.println(s.getValue_type() + ":" + s.getValue());
}
}

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.*;
import java.util.HashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.handler.BaseSensorHandler.UpdateStatus;
import org.openhab.binding.luftdateninfo.internal.mock.NoiseHandlerExtension;
import org.openhab.binding.luftdateninfo.internal.mock.ThingMock;
import org.openhab.binding.luftdateninfo.internal.util.FileReader;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
/**
* The {@link NoiseHandlerTest} Test Noise Handler updates
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class NoiseHandlerTest {
@Test
public void testValidUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
NoiseHandlerExtension noiseHandler = new NoiseHandlerExtension(t);
String pmJson = FileReader.readFileInString("src/test/resources/noise-result.json");
if (pmJson != null) {
UpdateStatus result = noiseHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.OK, result);
assertEquals("Noise EQ", QuantityType.valueOf(51.0, SmartHomeUnits.DECIBEL),
noiseHandler.getNoiseEQCache());
assertEquals("Noise Min", QuantityType.valueOf(47.2, SmartHomeUnits.DECIBEL),
noiseHandler.getNoiseMinCache());
assertEquals("Noise Max", QuantityType.valueOf(57.0, SmartHomeUnits.DECIBEL),
noiseHandler.getNoiseMaxCache());
} else {
assertTrue(false);
}
}
@Test
public void testInvalidUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
NoiseHandlerExtension noiseHandler = new NoiseHandlerExtension(t);
String pmJson = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
if (pmJson != null) {
UpdateStatus result = noiseHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.VALUE_ERROR, result);
assertEquals("Values undefined", QuantityType.valueOf(-1, SmartHomeUnits.DECIBEL),
noiseHandler.getNoiseEQCache());
assertEquals("Values undefined", QuantityType.valueOf(-1, SmartHomeUnits.DECIBEL),
noiseHandler.getNoiseMinCache());
assertEquals("Values undefined", QuantityType.valueOf(-1, SmartHomeUnits.DECIBEL),
noiseHandler.getNoiseMaxCache());
} else {
assertTrue(false);
}
}
@Test
public void testEmptyUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
NoiseHandlerExtension noiseHandler = new NoiseHandlerExtension(t);
UpdateStatus result = noiseHandler.updateChannels("[]");
assertEquals("Valid update", UpdateStatus.VALUE_EMPTY, result);
}
@Test
public void testNullUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
NoiseHandlerExtension noiseHandler = new NoiseHandlerExtension(t);
UpdateStatus result = noiseHandler.updateChannels(null);
assertEquals("Valid update", UpdateStatus.CONNECTION_ERROR, result);
}
}

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.assertEquals;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.utils.NumberUtils;
/**
* The {@link NumberTest} Test rounding and converting Numbers
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class NumberTest {
@Test
public void testRoundingUp() {
double d1 = 1.95;
double d1r2 = NumberUtils.round(d1, 2);
assertEquals("Double 1.95, 2 places ", "1.95", Double.toString(d1r2));
// System.out.println("D1R2 " + d1r2);
double d1r1 = NumberUtils.round(d1, 1);
// System.out.println("D1R1 " + d1r1);
assertEquals("Double 1.95, 1 place ", "2.0", Double.toString(d1r1));
}
@Test
public void testRoundingDown() {
double d1 = 1.94;
double d1r2 = NumberUtils.round(d1, 2);
assertEquals("Double 1.94, 2 places ", "1.94", Double.toString(d1r2));
// System.out.println("D1R2 " + d1r2);
double d1r1 = NumberUtils.round(d1, 1);
// System.out.println("D1R1 " + d1r1);
assertEquals("Double 1.94, 1 place ", "1.9", Double.toString(d1r1));
}
@Test
public void testStringNumbers() {
String d1 = "1.94";
double d1r2 = NumberUtils.round(d1, 2);
assertEquals("Double 1.94, 2 places ", "1.94", Double.toString(d1r2));
// System.out.println("D1R2 " + d1r2);
double d1r1 = NumberUtils.round(d1, 1);
// System.out.println("D1R1 " + d1r1);
assertEquals("Double 1.94, 1 place ", "1.9", Double.toString(d1r1));
}
}

View File

@@ -0,0 +1,173 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal;
import static org.junit.Assert.*;
import java.util.HashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.handler.BaseSensorHandler.ConfigStatus;
import org.openhab.binding.luftdateninfo.internal.handler.BaseSensorHandler.LifecycleStatus;
import org.openhab.binding.luftdateninfo.internal.handler.BaseSensorHandler.UpdateStatus;
import org.openhab.binding.luftdateninfo.internal.mock.PMHandlerExtension;
import org.openhab.binding.luftdateninfo.internal.mock.ThingMock;
import org.openhab.binding.luftdateninfo.internal.util.FileReader;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link PMHandlerTest} Test Particualte Matter Handler - Config and updates
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class PMHandlerTest {
private Logger logger = LoggerFactory.getLogger(PMHandlerTest.class);
@Test
public void testValidConfigStatus() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
pmHandler.initialize();
logger.info("LC status: {}", pmHandler.getLifecycleStatus());
int retryCount = 0; // Test shall fail after max 10 seconds
while (pmHandler.getLifecycleStatus() != LifecycleStatus.RUNNING && retryCount < 20) {
try {
logger.info("LC running not reached - wait");
Thread.sleep(500);
retryCount++;
} catch (InterruptedException e) {
// nothing to do
}
}
/*
* Test if config status is 0 = CONFIG_OK for valid configuration. Take real int for comparison instead of
* BaseHandler constants - in case of change test needs to be adapted
*/
assertEquals("Handler Configuration status", ConfigStatus.OK, pmHandler.getConfigStatus());
}
@Test
public void testInvalidConfigStatus() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", -1);
t.setConfiguration(properties);
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
pmHandler.initialize();
logger.info("LC status: {}", pmHandler.getLifecycleStatus());
int retryCount = 0; // Test shall fail after max 10 seconds
while (pmHandler.getLifecycleStatus() != LifecycleStatus.RUNNING && retryCount < 20) {
try {
logger.info("LC running not reached - wait");
Thread.sleep(500);
retryCount++;
} catch (InterruptedException e) {
// nothing to do
}
}
/*
* Test if config status is 3 = CONFIG_SENSOR_NUMBER for invalid configuration with non-number sensorid. Take
* real int for comparison instead of BaseHandler constants - in case of change test needs to be adapted
*/
assertEquals("Handler Configuration status", ConfigStatus.SENSOR_ID_NEGATIVE, pmHandler.getConfigStatus());
}
@Test
public void testValidUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
pmHandler.initialize();
String pmJson = FileReader.readFileInString("src/test/resources/pm-result.json");
if (pmJson != null) {
UpdateStatus result = pmHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.OK, result);
assertEquals("PM25", QuantityType.valueOf(2.9, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE),
pmHandler.getPM25Cache());
assertEquals("PM100", QuantityType.valueOf(5.2, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE),
pmHandler.getPM100Cache());
} else {
assertTrue(false);
}
}
@Test
public void testInvalidUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
String pmJson = FileReader.readFileInString("src/test/resources/noise-result.json");
if (pmJson != null) {
UpdateStatus result = pmHandler.updateChannels(pmJson);
assertEquals("Valid update", UpdateStatus.VALUE_ERROR, result);
assertEquals("Values undefined", QuantityType.valueOf(-1, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE),
pmHandler.getPM25Cache());
assertEquals("Values undefined", QuantityType.valueOf(-1, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE),
pmHandler.getPM100Cache());
} else {
assertTrue(false);
}
}
@Test
public void testEmptyUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
UpdateStatus result = pmHandler.updateChannels("[]");
assertEquals("Valid update", UpdateStatus.VALUE_EMPTY, result);
}
@Test
public void testNullUpdate() {
ThingMock t = new ThingMock();
HashMap<String, Object> properties = new HashMap<String, Object>();
// String sensorid taken from thing-types.xml
properties.put("sensorid", 12345);
t.setConfiguration(properties);
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
UpdateStatus result = pmHandler.updateChannels(null);
assertEquals("Valid update", UpdateStatus.CONNECTION_ERROR, result);
}
}

View File

@@ -0,0 +1,56 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.mock;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.handler.ConditionHandler;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
/**
* The {@link NoiseHandlerExtension} Test Noise Handler Extension with additonal state queries
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class ConditionHandlerExtension extends ConditionHandler {
public ConditionHandlerExtension(Thing thing) {
super(thing);
}
public ConfigStatus getConfigStatus() {
return configStatus;
}
public UpdateStatus getUpdateStatus() {
return lastUpdateStatus;
}
public @Nullable State getTemperature() {
return temperatureCache;
}
public @Nullable State getHumidity() {
return humidityCache;
}
public @Nullable State getPressure() {
return pressureCache;
}
public @Nullable State getPressureSea() {
return pressureSeaCache;
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.mock;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.handler.NoiseHandler;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
/**
* The {@link NoiseHandlerExtension} Test Noise Handler Extension with additonal state queries
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class NoiseHandlerExtension extends NoiseHandler {
public NoiseHandlerExtension(Thing thing) {
super(thing);
}
public ConfigStatus getConfigStatus() {
return configStatus;
}
public UpdateStatus getUpdateStatus() {
return lastUpdateStatus;
}
public @Nullable State getNoiseEQCache() {
return noiseEQCache;
}
public @Nullable State getNoiseMinCache() {
return noiseMinCache;
}
public @Nullable State getNoiseMaxCache() {
return noiseMaxCache;
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.mock;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.luftdateninfo.internal.handler.PMHandler;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
/**
* The {@link PMHandlerExtension} Test Particualte Matter Handler Extension with additonal state queries
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class PMHandlerExtension extends PMHandler {
public PMHandlerExtension(Thing thing) {
super(thing);
}
public ConfigStatus getConfigStatus() {
return configStatus;
}
public UpdateStatus getUpdateStatus() {
return lastUpdateStatus;
}
public @Nullable State getPM25Cache() {
return pm25Cache;
}
public @Nullable State getPM100Cache() {
return pm100Cache;
}
}

View File

@@ -0,0 +1,149 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.mock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
/**
* The {@link ThingMock} Thing Mock
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class ThingMock implements Thing {
private Configuration config = new Configuration();
@Override
public @Nullable String getLabel() {
return null;
}
@Override
public void setLabel(@Nullable String label) {
}
@Override
public List<Channel> getChannels() {
return new ArrayList<Channel>();
}
@Override
public List<Channel> getChannelsOfGroup(String channelGroupId) {
return new ArrayList<Channel>();
}
@Override
public @Nullable Channel getChannel(String channelId) {
return null;
}
@Override
public @Nullable Channel getChannel(ChannelUID channelUID) {
return null;
}
@Override
public ThingStatus getStatus() {
return ThingStatus.UNKNOWN;
}
@Override
public ThingStatusInfo getStatusInfo() {
return new ThingStatusInfo(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "");
}
@Override
public void setStatusInfo(ThingStatusInfo status) {
}
@Override
public void setHandler(@Nullable ThingHandler thingHandler) {
}
@Override
public @Nullable ThingHandler getHandler() {
return null;
}
@Override
public @Nullable ThingUID getBridgeUID() {
return null;
}
@Override
public void setBridgeUID(@Nullable ThingUID bridgeUID) {
}
@Override
public Configuration getConfiguration() {
return config;
}
public void setConfiguration(Map<String, Object> m) {
config = new Configuration(m);
}
@Override
public ThingUID getUID() {
return new ThingUID("", "");
}
@Override
public ThingTypeUID getThingTypeUID() {
return new ThingTypeUID("");
}
@Override
public Map<String, String> getProperties() {
return new HashMap<String, String>();
}
@Override
public @Nullable String setProperty(String name, @Nullable String value) {
return null;
}
@Override
public void setProperties(Map<String, String> properties) {
}
@Override
public @Nullable String getLocation() {
return null;
}
@Override
public void setLocation(@Nullable String location) {
}
@Override
public boolean isEnabled() {
return false;
}
}

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.util;
import static org.junit.Assert.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.luftdateninfo.internal.utils.DateTimeUtils;
/**
* The {@link DateTimeTest} Test DateTimeFormatter provided in utils package
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class DateTimeTest {
@Test
public void testJSonTime() {
String jsonDateString = "2020-08-14 14:53:21";
try {
LocalDateTime dt = LocalDateTime.from(DateTimeUtils.DTF.parse(jsonDateString));
assertEquals("Day ", 14, dt.getDayOfMonth());
assertEquals("Month ", 8, dt.getMonthValue());
assertEquals("Year ", 2020, dt.getYear());
String s = dt.format(DateTimeUtils.DTF);
assertEquals("String ", jsonDateString, s);
} catch (DateTimeParseException e) {
assertFalse(true);
}
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.luftdateninfo.internal.util;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link FileReader} Helper Util to read test resource files
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class FileReader {
public static @Nullable String readFileInString(String filename) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "CP1252"));) {
StringBuffer buf = new StringBuffer();
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
buf.append(sCurrentLine);
}
return buf.toString();
} catch (IOException e) {
// fail if file cannot be read
assertTrue(false);
}
return null;
}
}

View File

@@ -0,0 +1,73 @@
[
{
"id": 731117559,
"sensordatavalues": [
{
"id": 1573660194,
"value_type": "temperature",
"value": "22.70"
},
{
"id": 1573660195,
"value_type": "humidity",
"value": "61.00"
}
],
"timestamp": "2020-06-09 06:40:34",
"sampling_rate": null,
"location": {
"id": 11447,
"country": "DE",
"altitude": "151.5",
"latitude": "50.562",
"longitude": "8.504",
"indoor": 0,
"exact_location": 0
},
"sensor": {
"id": 22562,
"pin": "7",
"sensor_type": {
"id": 9,
"manufacturer": "various",
"name": "DHT22"
}
}
},
{
"id": 731094694,
"sensordatavalues": [
{
"id": 1573610869,
"value_type": "temperature",
"value": "22.50"
},
{
"id": 1573610870,
"value_type": "humidity",
"value": "62.00"
}
],
"timestamp": "2020-06-09 06:38:08",
"sampling_ra
te": null,
"location": {
"id": 11447,
"country": "DE",
"altitude": "151.5",
"latitude": "50.562",
"longitude": "8.504",
"indoor": 0,
"exact_location": 0
},
"sensor": {
"id": 22562,
"pin": "7",
"sensor_type": {
"id": 9,
"manufacturer": "various",
"name": "DHT22"
}
}
}
]

View File

@@ -0,0 +1,72 @@
[
{
"id": 731094694,
"sensordatavalues": [
{
"id": 1573610869,
"value_type": "temperature",
"value": "22.50"
},
{
"id": 1573610870,
"value_type": "humidity",
"value": "62.00"
}
],
"timestamp": "2020-06-09 06:38:08",
"sampling_rate": null,
"location": {
"id": 11447,
"country": "DE",
"altitude": "151.5",
"latitude": "50.562",
"longitude": "8.504",
"indoor": 0,
"exact_location": 0
},
"sensor": {
"id": 22562,
"pin": "7",
"sensor_type": {
"id": 9,
"manufacturer": "various",
"name": "DHT22"
}
}
},
{
"id": 731117559,
"sensordatavalues": [
{
"id": 1573660194,
"value_type": "temperature",
"value": "22.70"
},
{
"id": 1573660195,
"value_type": "humidity",
"value": "61.00"
}
],
"timestamp": "2020-06-09 06:40:34",
"sampling_rate": null,
"location": {
"id": 11447,
"country": "DE",
"altitude": "151.5",
"latitude": "50.562",
"longitude": "8.504",
"indoor": 0,
"exact_location": 0
},
"sensor": {
"id": 22562,
"pin": "7",
"sensor_type": {
"id": 9,
"manufacturer": "various",
"name": "DHT22"
}
}
}
]

View File

@@ -0,0 +1,90 @@
[
{
"id": 1038856661,
"sensor": {
"id": 28843,
"sensor_type": {
"id": 17,
"manufacturer": "Bosch",
"name": "BME280"
},
"pin": "11"
},
"timestamp": "2020-07-03 09:39:46",
"sampling_rate": null,
"location": {
"id": 15975,
"altitude": "151.2",
"longitude": "8.49543571448",
"exact_location": 1,
"latitude": "50.55591005174",
"indoor": 0,
"country": "DE"
},
"sensordatavalues": [
{
"id": 2237770681,
"value_type": "temperature",
"value": "21.52"
},
{
"id": 2237770683,
"value_type": "pressure",
"value": "100199.97"
},
{
"id": 2237770684,
"value_type": "humidity",
"value": "58.51"
},
{
"value_type": "pressure_at_sealevel",
"value": 101968.66
}
]
},
{
"id": 1038834126,
"sensor": {
"id": 28843,
"sensor_type": {
"id": 17,
"manufacturer": "Bosch",
"name": "BME280"
},
"pin": "11"
},
"timestamp": "2020-07-03 09:37:21",
"sampling_rate": null,
"location": {
"id": 15975,
"altitude": "151.2",
"longitude": "8.49543571448",
"exact_location": 1,
"latitude": "50.55591005174",
"indoor": 0,
"country": "DE"
},
"sensordatavalues": [
{
"id": 2237722004,
"value_type": "temperature",
"value": "21.45"
},
{
"id": 2237722008,
"value_type": "pressure",
"value": "100205.09"
},
{
"id": 2237722009,
"value_type": "humidity",
"value": "58.79"
},
{
"value_type": "pressure_at_sealevel",
"value": 101974.29
}
]
}
]

View File

@@ -0,0 +1,82 @@
[
{
"timestamp": "2020-06-11 09:39:51",
"sensordatavalues": [
{
"value": "50.95",
"id": 1629930130,
"value_type": "noise_LAeq"
},
{
"value": "47.20",
"id": 1629930131,
"value_type": "noise_LA_min"
},
{
"value": "56.95",
"id": 1629930132,
"value_type": "noise_LA_max"
}
],
"sampling_rate": null,
"location": {
"exact_location": 1,
"latitude": "50.88827895000",
"country": "DE",
"altitude": "294.9",
"indoor": 0,
"longitude": "7.87451286686",
"id": 25429
},
"id": 757217220,
"sensor": {
"sensor_type": {
"id": 29,
"manufacturer": "Luftdaten.info",
"name": "Laerm"
},
"pin": "15",
"id": 39745
}
},
{
"timestamp": "2020-06-11 09:37:25",
"sensordatavalues": [
{
"value": "52.02",
"id": 1629881984,
"value_type": "noise_LAeq"
},
{
"value": "45.98",
"id": 1629881986,
"value_type": "noise_LA_min"
},
{
"value": "69.28",
"id": 1629881987,
"value_type": "noise_LA_max"
}
],
"sampling_rate": null,
"location": {
"exact_location": 1,
"latitude": "50.88827895000",
"country": "DE",
"altitude": "294.9",
"indoor": 0,
"longitude": "7.87451286686",
"id": 25429
},
"id": 757194885,
"sensor": {
"sensor_type": {
"id": 29,
"manufacturer": "Luftdaten.info",
"name": "Laerm"
},
"pin": "15",
"id": 39745
}
}
]

View File

@@ -0,0 +1,72 @@
[
{
"timestamp": "2020-06-11 09:40:41",
"sensordatavalues": [
{
"value": "5.15",
"id": 1629948185,
"value_type": "P1"
},
{
"value": "2.87",
"id": 1629948191,
"value_type": "P2"
}
],
"sampling_rate": null,
"location": {
"exact_location": 1,
"latitude": "50.55591005174",
"country": "DE",
"altitude": "151.2",
"indoor": 0,
"longitude": "8.49543571448",
"id": 15975
},
"id": 757225623,
"sensor": {
"sensor_type": {
"id": 14,
"manufacturer": "Nova Fitness",
"name": "SDS011"
},
"pin": "1",
"id": 28842
}
},
{
"timestamp": "2020-06-11 09:38:16",
"sensordatavalues": [
{
"value": "2.20",
"id": 1629900061,
"value_type": "P1"
},
{
"value": "2.00",
"id": 1629900063,
"value_type": "P2"
}
],
"sampling_rate": null,
"location": {
"exact_location": 1,
"latitude": "50.55591005174",
"country": "DE",
"altitude": "151.2",
"indoor": 0,
"longitude": "8.49543571448",
"id": 15975
},
"id": 757203291,
"sensor": {
"sensor_type": {
"id": 14,
"manufacturer": "Nova Fitness",
"name": "SDS011"
},
"pin": "1",
"id": 28842
}
}
]