[luftdateninfo] Add internal sensor support (#10643)

Signed-off-by: Bernd Weymann <bernd.weymann@gmail.com>
This commit is contained in:
Bernd Weymann
2021-05-13 16:26:17 +02:00
committed by GitHub
parent db05079e6f
commit bafa841390
17 changed files with 256 additions and 78 deletions

View File

@@ -13,6 +13,7 @@
package org.openhab.binding.luftdateninfo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.luftdateninfo.internal.utils.Constants;
/**
* The {@link LuftdatenInfoConfiguration} class contains fields mapping thing configuration parameters.
@@ -22,5 +23,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
@NonNullByDefault
public class LuftdatenInfoConfiguration {
public int sensorid = -1;
public int sensorid = Constants.UNDEF;
public String ipAddress = Constants.EMPTY;
}

View File

@@ -48,13 +48,9 @@ public class LuftdatenInfoHandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
if (thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_PARTICULATE)
return (thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_PARTICULATE)
|| thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_CONDITIONS)
|| thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_NOISE)) {
return true;
} else {
return false;
}
|| thingTypeUID.equals(LuftdatenInfoBindingConstants.THING_TYPE_NOISE));
}
@Override

View File

@@ -13,12 +13,14 @@
package org.openhab.binding.luftdateninfo.internal.handler;
import java.time.LocalDateTime;
import java.util.Optional;
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.Constants;
import org.openhab.binding.luftdateninfo.internal.utils.DateTimeUtils;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
@@ -48,9 +50,12 @@ public abstract class BaseSensorHandler extends BaseThingHandler {
protected ThingStatus myThingStatus = ThingStatus.UNKNOWN;
protected UpdateStatus lastUpdateStatus = UpdateStatus.UNKNOWN;
protected @Nullable ScheduledFuture<?> refreshJob;
private Optional<String> sensorUrl = Optional.empty();
private boolean firstUpdate = true;
public enum ConfigStatus {
OK,
INTERNAL_SENSOR_OK,
EXTERNAL_SENSOR_OK,
IS_NULL,
SENSOR_IS_NULL,
SENSOR_ID_NEGATIVE,
@@ -88,6 +93,7 @@ public abstract class BaseSensorHandler extends BaseThingHandler {
@Override
public void initialize() {
firstUpdate = true;
lifecycleStatus = LifecycleStatus.INITIALIZING;
scheduler.execute(this::startUp);
}
@@ -95,7 +101,7 @@ public abstract class BaseSensorHandler extends BaseThingHandler {
private void startUp() {
config = getConfigAs(LuftdatenInfoConfiguration.class);
configStatus = checkConfig(config);
if (configStatus == ConfigStatus.OK) {
if (configStatus == ConfigStatus.INTERNAL_SENSOR_OK || configStatus == ConfigStatus.EXTERNAL_SENSOR_OK) {
// start getting values
dataUpdate();
} else {
@@ -135,10 +141,16 @@ public abstract class BaseSensorHandler extends BaseThingHandler {
*/
private ConfigStatus checkConfig(@Nullable LuftdatenInfoConfiguration c) {
if (c != null) {
if (c.sensorid >= 0) {
return ConfigStatus.OK;
if (c.ipAddress != null && !Constants.EMPTY.equals(c.ipAddress)) {
sensorUrl = Optional.of("http://" + c.ipAddress + "/data.json");
return ConfigStatus.INTERNAL_SENSOR_OK;
} else {
return ConfigStatus.SENSOR_ID_NEGATIVE;
if (c.sensorid >= 0) {
sensorUrl = Optional.of("http://data.sensor.community/airrohr/v1/sensor/" + c.sensorid + "/");
return ConfigStatus.EXTERNAL_SENSOR_OK;
} else {
return ConfigStatus.SENSOR_ID_NEGATIVE;
}
}
} else {
return ConfigStatus.IS_NULL;
@@ -150,11 +162,21 @@ public abstract class BaseSensorHandler extends BaseThingHandler {
}
protected void dataUpdate() {
HTTPHandler.getHandler().request(config.sensorid, this);
if (sensorUrl.isPresent()) {
HTTPHandler.getHandler().request(sensorUrl.get(), this);
}
}
public void onResponse(String data) {
lastUpdateStatus = updateChannels(data);
if (firstUpdate) {
logger.debug("{} delivers {}", sensorUrl.get(), data);
firstUpdate = false;
}
if (configStatus == ConfigStatus.INTERNAL_SENSOR_OK) {
lastUpdateStatus = updateChannels("[" + data + "]");
} else {
lastUpdateStatus = updateChannels(data);
}
statusUpdate(lastUpdateStatus, EMPTY);
}

View File

@@ -13,7 +13,8 @@
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 static org.openhab.binding.luftdateninfo.internal.utils.Constants.*;
import static org.openhab.core.library.unit.MetricPrefix.HECTO;
import java.util.List;
@@ -38,11 +39,10 @@ import org.openhab.core.thing.Thing;
*/
@NonNullByDefault
public class ConditionHandler extends BaseSensorHandler {
protected QuantityType<Temperature> temperatureCache = QuantityType.valueOf(-1, SIUnits.CELSIUS);
protected QuantityType<Dimensionless> humidityCache = QuantityType.valueOf(-1, Units.PERCENT);
protected QuantityType<Pressure> pressureCache = QuantityType.valueOf(-1, SIUnits.PASCAL);
protected QuantityType<Pressure> pressureSeaCache = QuantityType.valueOf(-1, SIUnits.PASCAL);
protected QuantityType<Pressure> pressureCache = QuantityType.valueOf(-1, HECTO(SIUnits.PASCAL));
protected QuantityType<Pressure> pressureSeaCache = QuantityType.valueOf(-1, HECTO(SIUnits.PASCAL));
public ConditionHandler(Thing thing) {
super(thing);
@@ -55,18 +55,22 @@ public class ConditionHandler extends BaseSensorHandler {
if (valueList != null) {
if (HTTPHandler.getHandler().isCondition(valueList)) {
valueList.forEach(v -> {
if (v.getValueType().equals(TEMPERATURE)) {
if (v.getValueType().endsWith(TEMPERATURE)) {
temperatureCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
SIUnits.CELSIUS);
updateState(TEMPERATURE_CHANNEL, temperatureCache);
} else if (v.getValueType().equals(HUMIDITY)) {
} else if (v.getValueType().endsWith(HUMIDITY)) {
humidityCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.PERCENT);
updateState(HUMIDITY_CHANNEL, humidityCache);
} else if (v.getValueType().equals(PRESSURE)) {
pressureCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), SIUnits.PASCAL);
} else if (v.getValueType().endsWith(PRESSURE)) {
pressureCache = QuantityType.valueOf(
NumberUtils.round(NumberUtils.convert(v.getValue()) / 100, 1),
HECTO(SIUnits.PASCAL));
updateState(PRESSURE_CHANNEL, pressureCache);
} else if (v.getValueType().equals(PRESSURE_SEALEVEL)) {
pressureSeaCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), SIUnits.PASCAL);
} else if (v.getValueType().endsWith(PRESSURE_SEALEVEL)) {
pressureSeaCache = QuantityType.valueOf(
NumberUtils.round(NumberUtils.convert(v.getValue()) / 100, 1),
HECTO(SIUnits.PASCAL));
updateState(PRESSURE_SEA_CHANNEL, pressureSeaCache);
}
});

View File

@@ -12,6 +12,8 @@
*/
package org.openhab.binding.luftdateninfo.internal.handler;
import static org.openhab.binding.luftdateninfo.internal.utils.Constants.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@@ -42,19 +44,6 @@ public class HTTPHandler {
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) {
@@ -65,12 +54,11 @@ public class HTTPHandler {
return HTTP_HANDLER;
}
public synchronized void request(int sensorId, BaseSensorHandler callback) {
public synchronized void request(String url, 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({})
@@ -142,7 +130,7 @@ public class HTTPHandler {
if (valueList == null) {
return false;
}
return valueList.stream().map(v -> v.getValueType()).filter(t -> t.equals(P1) || t.equals(P2)).findAny()
return valueList.stream().map(v -> v.getValueType()).filter(t -> t.endsWith(P1) || t.endsWith(P2)).findAny()
.isPresent();
}
@@ -150,9 +138,8 @@ public class HTTPHandler {
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();
return valueList.stream().map(v -> v.getValueType()).filter(t -> t.equals(TEMPERATURE) || t.endsWith(HUMIDITY)
|| t.endsWith(PRESSURE) || t.endsWith(PRESSURE_SEALEVEL)).findAny().isPresent();
}
public boolean isNoise(@Nullable List<SensorDataValue> valueList) {
@@ -160,6 +147,7 @@ public class HTTPHandler {
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();
.filter(t -> t.endsWith(NOISE_EQ) || t.endsWith(NOISE_MAX) || t.endsWith(NOISE_MIN)).findAny()
.isPresent();
}
}

View File

@@ -13,7 +13,7 @@
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 static org.openhab.binding.luftdateninfo.internal.utils.Constants.*;
import java.util.List;
@@ -50,13 +50,13 @@ public class NoiseHandler extends BaseSensorHandler {
if (valueList != null) {
if (HTTPHandler.getHandler().isNoise(valueList)) {
valueList.forEach(v -> {
if (v.getValueType().equals(NOISE_EQ)) {
if (v.getValueType().endsWith(NOISE_EQ)) {
noiseEQCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.DECIBEL);
updateState(NOISE_EQ_CHANNEL, noiseEQCache);
} else if (v.getValueType().equals(NOISE_MIN)) {
} else if (v.getValueType().endsWith(NOISE_MIN)) {
noiseMinCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.DECIBEL);
updateState(NOISE_MIN_CHANNEL, noiseMinCache);
} else if (v.getValueType().equals(NOISE_MAX)) {
} else if (v.getValueType().endsWith(NOISE_MAX)) {
noiseMaxCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.DECIBEL);
updateState(NOISE_MAX_CHANNEL, noiseMaxCache);
}

View File

@@ -13,7 +13,7 @@
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 static org.openhab.binding.luftdateninfo.internal.utils.Constants.*;
import java.util.List;
@@ -49,11 +49,11 @@ public class PMHandler extends BaseSensorHandler {
if (valueList != null) {
if (HTTPHandler.getHandler().isParticulate(valueList)) {
valueList.forEach(v -> {
if (v.getValueType().equals(P1)) {
if (v.getValueType().endsWith(P1)) {
pm100Cache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
Units.MICROGRAM_PER_CUBICMETRE);
updateState(PM100_CHANNEL, pm100Cache);
} else if (v.getValueType().equals(P2)) {
} else if (v.getValueType().endsWith(P2)) {
pm25Cache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
Units.MICROGRAM_PER_CUBICMETRE);
updateState(PM25_CHANNEL, pm25Cache);

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2021 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 Constants} Constants used in this binding
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class Constants {
public static final String EMPTY = "";
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";
public static final int UNDEF = -1;
}

View File

@@ -14,9 +14,14 @@
</channels>
<config-description>
<parameter name="sensorid" type="integer" required="true">
<label>Sensor ID</label>
<description>Sensor ID</description>
<parameter name="ipAddress" type="text">
<context>network-address</context>
<label>Internal IP Address</label>
<description>Local IP address of your personal owned sensor</description>
</parameter>
<parameter name="sensorid" type="integer">
<label>External Sensor ID</label>
<description>Sensor ID from https://deutschland.maps.sensor.community/</description>
</parameter>
</config-description>
</thing-type>
@@ -33,9 +38,14 @@
</channels>
<config-description>
<parameter name="sensorid" type="integer" required="true">
<label>Sensor ID</label>
<description>Sensor ID</description>
<parameter name="ipAddress" type="text">
<context>network-address</context>
<label>Internal IP Address</label>
<description>Local IP address of your personal owned sensor</description>
</parameter>
<parameter name="sensorid" type="integer">
<label>External Sensor ID</label>
<description>Sensor ID from https://deutschland.maps.sensor.community/</description>
</parameter>
</config-description>
</thing-type>
@@ -51,9 +61,14 @@
</channels>
<config-description>
<parameter name="sensorid" type="integer" required="true">
<label>Sensor ID</label>
<description>Sensor ID</description>
<parameter name="ipAddress" type="text">
<context>network-address</context>
<label>Internal IP Address</label>
<description>Local IP address of your personal owned sensor</description>
</parameter>
<parameter name="sensorid" type="integer">
<label>External Sensor ID</label>
<description>Sensor ID from https://deutschland.maps.sensor.community/</description>
</parameter>
</config-description>
</thing-type>
@@ -61,44 +76,53 @@
<channel-type id="pm25-channel">
<item-type>Number:Density</item-type>
<label>Particulate Matter category 2.5</label>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="pm100-channel">
<item-type>Number:Density</item-type>
<label>Particulate Matter category 10.0</label>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temp-channel">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Temperature from the selected Sensor ID</description>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="hum-channel">
<item-type>Number:Dimensionless</item-type>
<label>Humidity</label>
<description>Humidity from the selected Sensor ID</description>
<state pattern="%.1f %unit%" readOnly="true"/>
</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>
<state pattern="%.1f %unit%" readOnly="true"/>
</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>
<state pattern="%.1f %unit%" readOnly="true"/>
</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>
<state pattern="%.1f %unit%" readOnly="true"/>
</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>
<state pattern="%.1f %unit%" readOnly="true"/>
</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>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>