[luftdateninfo][sensorcommunity] Rename binding to Sensor.Community (#15012)
* [luftdateninfo][sensorcommunity] Rename binding to match the new name Sensor.Community Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
This commit is contained in:
13
bundles/org.openhab.binding.sensorcommunity/NOTICE
Normal file
13
bundles/org.openhab.binding.sensorcommunity/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
121
bundles/org.openhab.binding.sensorcommunity/README.md
Normal file
121
bundles/org.openhab.binding.sensorcommunity/README.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# SensorCommunity Binding
|
||||
|
||||
Binding for the [Sensor.Community](https://sensor.community/).
|
||||
The community provides instructions to build sensors on your own and they can be integrated into the database.
|
||||
With this binding you can integrate your sensor, a sensor nearby or even any sensors you want into openHAB.
|
||||
|
||||
## Supported Things
|
||||
|
||||
Three Things are supported
|
||||
|
||||
| Name | Thing Type ID | Description |
|
||||
|--------------------|---------------|--------------------------------------------------------------------------------------------------------|
|
||||
| Particulate Sensor | particulate | measure particulate matter PM2.5 and PM10 |
|
||||
| Conditions Sensor | condition | measures environment conditions like temperature, humidity and some also provides atmospheric pressure |
|
||||
| Noise Sensor | noise | measures noise exposures in the environment |
|
||||
|
||||
## Discovery
|
||||
|
||||
There's no auto discovery. See Thing configuration how to setup a Sensor.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
Choose either a local IP address of your personal owned sensor _or_ a sensor id of an external one.
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------------|----------------------------------------------------------------------|
|
||||
| ipAddress | Local IP address of your personal owned sensor |
|
||||
| sensorid | Sensor ID obtained from <https://deutschland.maps.sensor.community/> |
|
||||
|
||||
### Local Sensor
|
||||
|
||||
Please check in your browser if you can access your sensor with your local IP address.
|
||||
|
||||

|
||||
|
||||
### External Sensor
|
||||
|
||||
Perform the following steps to get the appropriate Sensor ID
|
||||
|
||||
- Go to to [Sensor.Community map](https://deutschland.maps.sensor.community/)
|
||||
- Choose your desired value in bottom list - now only the Sensors are displayed which are supporting this
|
||||
- Click on your / any Sensor and the ID is displayed in the top right corner. Note: Sensor ID is just the number without beginning hash #
|
||||
- Enter this Sensor ID into the thing configuration
|
||||
|
||||

|
||||
|
||||
## Channels
|
||||
|
||||
### Particulate Sensor
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|----------------------|----------------------|------------------------------------------|
|
||||
| pm25 | Number:Density | [Ultrafine particulates](https://en.wikipedia.org/wiki/Particulates#Size,_shape_and_solubility_matter) microgram per cubic meter |
|
||||
| pm100 | Number:Density | [Coarse particulate matter](https://en.wikipedia.org/wiki/Particulates#Size,_shape_and_solubility_matter) microgram per cubic meter |
|
||||
|
||||
### Conditions Sensor
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|----------------------|----------------------|------------------------------------------|
|
||||
| temperature | Number:Temperature | current temperature |
|
||||
| humidity | Number:Dimensionless | current humidity percent |
|
||||
| pressure | Number:Pressure | Atmospheric Pressure (not supported by all sensors) |
|
||||
| pressure-sea | Number:Pressure | Atmospheric Pressure on sea level (not supported by all sensors) |
|
||||
|
||||
### Noise Sensor
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|----------------------|----------------------|------------------------------------------------------|
|
||||
| noise-eq | Number:Dimensionless | Average noise in db |
|
||||
| noise-min | Number:Dimensionless | Minimum noise covered in the last 2.5 minutes in db |
|
||||
| noise-main | Number:Dimensionless | Maximum noise covered in the last 2.5 minutes in db |
|
||||
|
||||
## Full Example
|
||||
|
||||
### Things
|
||||
|
||||
sensorcommunity.things
|
||||
|
||||
```java
|
||||
Thing sensorcommunity:particulate:pm_sensor "PM Sensor" [ ipAddress=192.168.178.50 ]
|
||||
Thing sensorcommunity:conditions:cond_sensor "Condition Sensor" [ sensorid=28843 ]
|
||||
Thing sensorcommunity:noise:noise_sensor "Noise Sensor" [ sensorid=39745 ]
|
||||
```
|
||||
|
||||
### Items
|
||||
|
||||
sensorcommunity.items
|
||||
|
||||
```java
|
||||
Number:Density PM_25 "PM2.5" { channel="sensorcommunity:particulate:pm_sensor:pm25" }
|
||||
Number:Density PM_100 "PM10" { channel="sensorcommunity:particulate:pm_sensor:pm100" }
|
||||
|
||||
Number:Temperature LDI_Temperature "Temperature" { channel="sensorcommunity:conditions:cond_sensor:temperature" }
|
||||
Number:Dimensionless LDI_Humidity "Humidity" { channel="sensorcommunity:conditions:cond_sensor:humidity" }
|
||||
Number:Pressure LDI_Pressure "Atmospheric Pressure" { channel="sensorcommunity:conditions:cond_sensor:pressure" }
|
||||
Number:Pressure LDI_PressureSea "Pressure sea level" { channel="sensorcommunity:conditions:cond_sensor:pressure-sea" }
|
||||
|
||||
Number:Dimensionless LDI_NoiseEQ "Noise EQ" { channel="sensorcommunity:noise:noise_sensor:noise-eq" }
|
||||
Number:Dimensionless LDI_NoiseMin "Noise min" { channel="sensorcommunity:noise:noise_sensor:noise-min" }
|
||||
Number:Dimensionless LDI_NoiseMax "Noise max" { channel="sensorcommunity:noise:noise_sensor:noise-max" }
|
||||
```
|
||||
|
||||
### Sitemap
|
||||
|
||||
SensorCommunity.sitemap
|
||||
|
||||
```perl
|
||||
sitemap SensorCommunity label="SensorCommunity" {
|
||||
Text item=PM_25 label="Particulate Matter 2.5 [%.1f %unit%]"
|
||||
Text item=PM_100 label="Particulate Matter 10 [%.1f %unit%]"
|
||||
|
||||
Text item=LDI_Temperature label="Temperature [%d %unit%]"
|
||||
Text item=LDI_Humidity label="Humidity [%d %unit%]"
|
||||
Text item=LDI_Pressure label="Atmospheric Pressure [%d %unit%]"
|
||||
Text item=LDI_PressureSea label="Atmospheric Pressure sea [%d %unit%]"
|
||||
|
||||
Text item=LDI_NoiseEQ label="Noise avg [%.1f %unit%]"
|
||||
Text item=LDI_NoiseMin label="Noise min [%.1f %unit%]"
|
||||
Text item=LDI_NoiseMax label="Noise max [%.1f %unit%]"
|
||||
}
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 910 KiB |
BIN
bundles/org.openhab.binding.sensorcommunity/doc/local-sensor.png
Normal file
BIN
bundles/org.openhab.binding.sensorcommunity/doc/local-sensor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
16
bundles/org.openhab.binding.sensorcommunity/pom.xml
Normal file
16
bundles/org.openhab.binding.sensorcommunity/pom.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.sensorcommunity</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Sensor.Community Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.sensorcommunity-${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-sensorcommunity" description="Sensor.Community Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.sensorcommunity/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SensorCommunityBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Bernd Weymann - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SensorCommunityBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "sensorcommunity";
|
||||
|
||||
// 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";
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.Constants;
|
||||
|
||||
/**
|
||||
* The {@link SensorCommunityConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Bernd Weymann - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SensorCommunityConfiguration {
|
||||
|
||||
public int sensorid = Constants.UNDEF;
|
||||
|
||||
public String ipAddress = Constants.EMPTY;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.ConditionHandler;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.HTTPHandler;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.NoiseHandler;
|
||||
import org.openhab.binding.sensorcommunity.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 SensorCommunityHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Bernd Weymann - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.sensorcommunity", service = ThingHandlerFactory.class)
|
||||
public class SensorCommunityHandlerFactory extends BaseThingHandlerFactory {
|
||||
protected final Logger logger = LoggerFactory.getLogger(SensorCommunityHandlerFactory.class);
|
||||
|
||||
@Activate
|
||||
public SensorCommunityHandlerFactory(final @Reference HttpClientFactory httpClientFactory) {
|
||||
HTTPHandler.init(httpClientFactory.getCommonHttpClient());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return (thingTypeUID.equals(SensorCommunityBindingConstants.THING_TYPE_PARTICULATE)
|
||||
|| thingTypeUID.equals(SensorCommunityBindingConstants.THING_TYPE_CONDITIONS)
|
||||
|| thingTypeUID.equals(SensorCommunityBindingConstants.THING_TYPE_NOISE));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
if (thing.getThingTypeUID().equals(SensorCommunityBindingConstants.THING_TYPE_PARTICULATE)) {
|
||||
return new PMHandler(thing);
|
||||
} else if (thing.getThingTypeUID().equals(SensorCommunityBindingConstants.THING_TYPE_CONDITIONS)) {
|
||||
return new ConditionHandler(thing);
|
||||
} else if (thing.getThingTypeUID().equals(SensorCommunityBindingConstants.THING_TYPE_NOISE)) {
|
||||
return new NoiseHandler(thing);
|
||||
}
|
||||
logger.info("Handler for {} not found", thing.getThingTypeUID());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SensorCommunity} 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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.sensorcommunity.internal.SensorCommunityConfiguration;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.Constants;
|
||||
import org.openhab.binding.sensorcommunity.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 SensorCommunityConfiguration DEFAULT_CONFIG = new SensorCommunityConfiguration();
|
||||
private static final String EMPTY = "";
|
||||
|
||||
protected static final int REFRESH_INTERVAL_MIN = 5;
|
||||
protected final Logger logger = LoggerFactory.getLogger(BaseSensorHandler.class);
|
||||
protected SensorCommunityConfiguration config = DEFAULT_CONFIG;
|
||||
protected ConfigStatus configStatus = ConfigStatus.UNKNOWN;
|
||||
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 {
|
||||
INTERNAL_SENSOR_OK,
|
||||
EXTERNAL_SENSOR_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() {
|
||||
firstUpdate = true;
|
||||
lifecycleStatus = LifecycleStatus.INITIALIZING;
|
||||
scheduler.execute(this::startUp);
|
||||
}
|
||||
|
||||
private void startUp() {
|
||||
config = getConfigAs(SensorCommunityConfiguration.class);
|
||||
configStatus = checkConfig(config);
|
||||
if (configStatus == ConfigStatus.INTERNAL_SENSOR_OK || configStatus == ConfigStatus.EXTERNAL_SENSOR_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 SensorCommunityConfiguration c) {
|
||||
if (c != null) {
|
||||
if (c.ipAddress != null && !Constants.EMPTY.equals(c.ipAddress)) {
|
||||
sensorUrl = Optional.of("http://" + c.ipAddress + "/data.json");
|
||||
return ConfigStatus.INTERNAL_SENSOR_OK;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public LifecycleStatus getLifecycleStatus() {
|
||||
return lifecycleStatus;
|
||||
}
|
||||
|
||||
protected void dataUpdate() {
|
||||
if (sensorUrl.isPresent()) {
|
||||
HTTPHandler.getHandler().request(sensorUrl.get(), this);
|
||||
}
|
||||
}
|
||||
|
||||
public void onResponse(String 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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sensorcommunity.internal.SensorCommunityBindingConstants.*;
|
||||
import static org.openhab.binding.sensorcommunity.internal.utils.Constants.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.HECTO;
|
||||
|
||||
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.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.NumberUtils;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
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, Units.PERCENT);
|
||||
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);
|
||||
}
|
||||
|
||||
@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().endsWith(TEMPERATURE)) {
|
||||
temperatureCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
|
||||
SIUnits.CELSIUS);
|
||||
updateState(TEMPERATURE_CHANNEL, temperatureCache);
|
||||
} else if (v.getValueType().endsWith(HUMIDITY)) {
|
||||
humidityCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.PERCENT);
|
||||
updateState(HUMIDITY_CHANNEL, humidityCache);
|
||||
} 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().endsWith(PRESSURE_SEALEVEL)) {
|
||||
pressureSeaCache = QuantityType.valueOf(
|
||||
NumberUtils.round(NumberUtils.convert(v.getValue()) / 100, 1),
|
||||
HECTO(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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sensorcommunity.internal.utils.Constants.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
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.sensorcommunity.internal.dto.SensorData;
|
||||
import org.openhab.binding.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.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();
|
||||
|
||||
private static @Nullable HttpClient commonHttpClient;
|
||||
|
||||
public static void init(HttpClient httpClient) {
|
||||
commonHttpClient = httpClient;
|
||||
}
|
||||
|
||||
public static HTTPHandler getHandler() {
|
||||
return HTTP_HANDLER;
|
||||
}
|
||||
|
||||
public synchronized void request(String url, BaseSensorHandler callback) {
|
||||
HttpClient localClient = commonHttpClient;
|
||||
if (localClient == null) {
|
||||
logger.warn("HTTP Client not initialized");
|
||||
} else {
|
||||
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(Objects.requireNonNullElse(failure, "Unknown error"));
|
||||
} 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.endsWith(P1) || t.endsWith(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.endsWith(HUMIDITY)
|
||||
|| t.endsWith(PRESSURE) || t.endsWith(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.endsWith(NOISE_EQ) || t.endsWith(NOISE_MAX) || t.endsWith(NOISE_MIN)).findAny()
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sensorcommunity.internal.SensorCommunityBindingConstants.*;
|
||||
import static org.openhab.binding.sensorcommunity.internal.utils.Constants.*;
|
||||
|
||||
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.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.NumberUtils;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
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, Units.DECIBEL);
|
||||
protected QuantityType<Dimensionless> noiseMinCache = QuantityType.valueOf(-1, Units.DECIBEL);
|
||||
protected QuantityType<Dimensionless> noiseMaxCache = QuantityType.valueOf(-1, Units.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().endsWith(NOISE_EQ)) {
|
||||
noiseEQCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.DECIBEL);
|
||||
updateState(NOISE_EQ_CHANNEL, noiseEQCache);
|
||||
} 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().endsWith(NOISE_MAX)) {
|
||||
noiseMaxCache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1), Units.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sensorcommunity.internal.SensorCommunityBindingConstants.*;
|
||||
import static org.openhab.binding.sensorcommunity.internal.utils.Constants.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.NumberUtils;
|
||||
import org.openhab.core.library.dimension.Density;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
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, Units.MICROGRAM_PER_CUBICMETRE);
|
||||
protected QuantityType<Density> pm100Cache = QuantityType.valueOf(-1, Units.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().endsWith(P1)) {
|
||||
pm100Cache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
|
||||
Units.MICROGRAM_PER_CUBICMETRE);
|
||||
updateState(PM100_CHANNEL, pm100Cache);
|
||||
} else if (v.getValueType().endsWith(P2)) {
|
||||
pm25Cache = QuantityType.valueOf(NumberUtils.round(v.getValue(), 1),
|
||||
Units.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="sensorcommunity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>Sensor.Community Binding</name>
|
||||
<description>Binding to integrate DIY Sensors from Sensor.Community</description>
|
||||
<connection>hybrid</connection>
|
||||
|
||||
</addon:addon>
|
||||
@@ -0,0 +1,47 @@
|
||||
# add-on
|
||||
|
||||
addon.sensorcommunity.name = Sensor.Community Binding
|
||||
addon.sensorcommunity.description = Binding to integrate DIY Sensors from Sensor.Community
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.sensorcommunity.conditions.label = Condition Sensor
|
||||
thing-type.sensorcommunity.conditions.description = Sensor to measure Temperature and Humidity conditions
|
||||
thing-type.sensorcommunity.noise.label = Noise Sensor
|
||||
thing-type.sensorcommunity.noise.description = Sensor to measure noise on location
|
||||
thing-type.sensorcommunity.particulate.label = Particulate Sensor
|
||||
thing-type.sensorcommunity.particulate.description = Sensor to measure Particulate Matter (PM)
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.sensorcommunity.conditions.ipAddress.label = Internal IP Address
|
||||
thing-type.config.sensorcommunity.conditions.ipAddress.description = Local IP address of your personal owned sensor
|
||||
thing-type.config.sensorcommunity.conditions.sensorid.label = External Sensor ID
|
||||
thing-type.config.sensorcommunity.conditions.sensorid.description = Sensor ID from https://deutschland.maps.sensor.community/
|
||||
thing-type.config.sensorcommunity.noise.ipAddress.label = Internal IP Address
|
||||
thing-type.config.sensorcommunity.noise.ipAddress.description = Local IP address of your personal owned sensor
|
||||
thing-type.config.sensorcommunity.noise.sensorid.label = External Sensor ID
|
||||
thing-type.config.sensorcommunity.noise.sensorid.description = Sensor ID from https://deutschland.maps.sensor.community/
|
||||
thing-type.config.sensorcommunity.particulate.ipAddress.label = Internal IP Address
|
||||
thing-type.config.sensorcommunity.particulate.ipAddress.description = Local IP address of your personal owned sensor
|
||||
thing-type.config.sensorcommunity.particulate.sensorid.label = External Sensor ID
|
||||
thing-type.config.sensorcommunity.particulate.sensorid.description = Sensor ID from https://deutschland.maps.sensor.community/
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.sensorcommunity.hum-channel.label = Humidity
|
||||
channel-type.sensorcommunity.hum-channel.description = Humidity from the selected Sensor ID
|
||||
channel-type.sensorcommunity.noise-eq-channel.label = Average Noise
|
||||
channel-type.sensorcommunity.noise-eq-channel.description = Average noise level from the selected Sensor ID
|
||||
channel-type.sensorcommunity.noise-max-channel.label = Maximum Noise
|
||||
channel-type.sensorcommunity.noise-max-channel.description = Maximum noise level (last 2.5 minutes) from the selected Sensor ID
|
||||
channel-type.sensorcommunity.noise-min-channel.label = Minimum Noise
|
||||
channel-type.sensorcommunity.noise-min-channel.description = Minimum noise level (last 2.5 minutes) from the selected Sensor ID
|
||||
channel-type.sensorcommunity.pm100-channel.label = Particulate Matter category 10.0
|
||||
channel-type.sensorcommunity.pm25-channel.label = Particulate Matter category 2.5
|
||||
channel-type.sensorcommunity.pressure-channel.label = Atmospheric Pressure
|
||||
channel-type.sensorcommunity.pressure-channel.description = Atmospheric Pressure from the selected Sensor ID
|
||||
channel-type.sensorcommunity.pressure-sea-channel.label = Atmospheric Pressure Sea Level
|
||||
channel-type.sensorcommunity.pressure-sea-channel.description = Atmospheric Pressure at sea level from the selected Sensor ID
|
||||
channel-type.sensorcommunity.temp-channel.label = Temperature
|
||||
channel-type.sensorcommunity.temp-channel.description = Temperature from the selected Sensor ID
|
||||
@@ -0,0 +1,47 @@
|
||||
# add-on
|
||||
|
||||
addon.sensorcommunity.name = Sensor.Community Binding
|
||||
addon.sensorcommunity.description = Das Binding stellt die Daten der Eigenbau-Sensoren von Sensor.Community zur Verfügung
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.sensorcommunity.conditions.label = Umweltsensor
|
||||
thing-type.sensorcommunity.conditions.description = Messung der Temperatur, Luftfeuchtigkeit und Luftdruck
|
||||
thing-type.sensorcommunity.noise.label = Lärmsensor
|
||||
thing-type.sensorcommunity.noise.description = Messung der Lärmbelastung in der Umgebung
|
||||
thing-type.sensorcommunity.particulate.label = Feinstaubsensor
|
||||
thing-type.sensorcommunity.particulate.description = Messung der Feinstaubbelastung in der Umgebung
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.sensorcommunity.conditions.ipAddress.label = Interne IP-Adresse
|
||||
thing-type.config.sensorcommunity.conditions.ipAddress.description = Lokale IP-Adresse Ihres persönlichen Sensors
|
||||
thing-type.config.sensorcommunity.conditions.sensorid.label = Externe Sensor-ID
|
||||
thing-type.config.sensorcommunity.conditions.sensorid.description = Sensor-ID von https\://deutschland.maps.sensor.community/
|
||||
thing-type.config.sensorcommunity.noise.ipAddress.label = Interne IP-Adresse
|
||||
thing-type.config.sensorcommunity.noise.ipAddress.description = Lokale IP-Adresse Ihres persönlichen Sensors
|
||||
thing-type.config.sensorcommunity.noise.sensorid.label = Externe Sensor-ID
|
||||
thing-type.config.sensorcommunity.noise.sensorid.description = Sensor-ID von https\://deutschland.maps.sensor.community/
|
||||
thing-type.config.sensorcommunity.particulate.ipAddress.label = Interne IP-Adresse
|
||||
thing-type.config.sensorcommunity.particulate.ipAddress.description = Lokale IP-Adresse Ihres persönlichen Sensors
|
||||
thing-type.config.sensorcommunity.particulate.sensorid.label = Externe Sensor-ID
|
||||
thing-type.config.sensorcommunity.particulate.sensorid.description = Sensor-ID von https\://deutschland.maps.sensor.community/
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.sensorcommunity.hum-channel.label = Luftfeuchtigkeit
|
||||
channel-type.sensorcommunity.hum-channel.description = Luftfeuchtigkeit der ausgewählten Sensor-ID
|
||||
channel-type.sensorcommunity.noise-eq-channel.label = Durchschnittlicher Lärmpegel
|
||||
channel-type.sensorcommunity.noise-eq-channel.description = Durchschnittlicher Rauschpegel der ausgewählten Sensor-ID
|
||||
channel-type.sensorcommunity.noise-max-channel.label = Maximaler Lärmpegel
|
||||
channel-type.sensorcommunity.noise-max-channel.description = Maximaler Rauschpegel (letzte 2,5 Minuten) der ausgewählten Sensor-ID
|
||||
channel-type.sensorcommunity.noise-min-channel.label = Minimaler Lärmpegel
|
||||
channel-type.sensorcommunity.noise-min-channel.description = Minimaler Rauschpegel (letzte 2,5 Minuten) der ausgewählten Sensor-ID
|
||||
channel-type.sensorcommunity.pm100-channel.label = Feinstaub der Kategorie PM 10.0
|
||||
channel-type.sensorcommunity.pm25-channel.label = Feinstaub der Kategorie PM 2.5
|
||||
channel-type.sensorcommunity.pressure-channel.label = Atmosphärischer Druck
|
||||
channel-type.sensorcommunity.pressure-channel.description = Atmosphärischer Druck der ausgewählten Sensor-ID
|
||||
channel-type.sensorcommunity.pressure-sea-channel.label = Atmosphärischer Druck Auf Meereshöhe
|
||||
channel-type.sensorcommunity.pressure-sea-channel.description = Atmosphärischer Druck auf Seehöhe der ausgewählten Sensor-ID
|
||||
channel-type.sensorcommunity.temp-channel.label = Temperatur
|
||||
channel-type.sensorcommunity.temp-channel.description = Temperatur der ausgewählten Sensor-ID
|
||||
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sensorcommunity"
|
||||
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="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>
|
||||
|
||||
<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="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>
|
||||
|
||||
<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="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>
|
||||
|
||||
<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>
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.HECTO;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.BaseSensorHandler.UpdateStatus;
|
||||
import org.openhab.binding.sensorcommunity.internal.mock.ConditionHandlerExtension;
|
||||
import org.openhab.binding.sensorcommunity.internal.mock.ThingMock;
|
||||
import org.openhab.binding.sensorcommunity.internal.util.FileReader;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
|
||||
/**
|
||||
* 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(UpdateStatus.OK, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(22.7, SIUnits.CELSIUS), condHandler.getTemperature(), "Temperature");
|
||||
assertEquals(QuantityType.valueOf(61., Units.PERCENT), condHandler.getHumidity(), "Humidity");
|
||||
assertEquals(QuantityType.valueOf(-1, HECTO(SIUnits.PASCAL)), condHandler.getPressure(), "Pressure");
|
||||
assertEquals(QuantityType.valueOf(-1, HECTO(SIUnits.PASCAL)), condHandler.getPressureSea(), "Pressure Sea");
|
||||
} 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(UpdateStatus.OK, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(21.5, SIUnits.CELSIUS), condHandler.getTemperature(), "Temperature");
|
||||
assertEquals(QuantityType.valueOf(58.5, Units.PERCENT), condHandler.getHumidity(), "Humidity");
|
||||
assertEquals(QuantityType.valueOf(1002.0, HECTO(SIUnits.PASCAL)), condHandler.getPressure(), "Pressure");
|
||||
assertEquals(QuantityType.valueOf(1019.7, HECTO(SIUnits.PASCAL)), condHandler.getPressureSea(),
|
||||
"Pressure Sea");
|
||||
} 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(UpdateStatus.VALUE_ERROR, result, "Valid update");
|
||||
} 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(UpdateStatus.VALUE_EMPTY, result, "Valid update");
|
||||
}
|
||||
|
||||
@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(UpdateStatus.CONNECTION_ERROR, result, "Valid update");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalUpdate() {
|
||||
ThingMock t = new ThingMock();
|
||||
|
||||
HashMap<String, Object> properties = new HashMap<String, Object>();
|
||||
// String sensorid taken from thing-types.xml
|
||||
properties.put("ipAddress", "192.168.178.1");
|
||||
t.setConfiguration(properties);
|
||||
|
||||
ConditionHandlerExtension condHandler = new ConditionHandlerExtension(t);
|
||||
String pmJson = FileReader.readFileInString("src/test/resources/internal-data.json");
|
||||
if (pmJson != null) {
|
||||
UpdateStatus result = condHandler.updateChannels("[" + pmJson + "]");
|
||||
assertEquals(UpdateStatus.OK, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(17.6, SIUnits.CELSIUS), condHandler.getTemperature(), "Temperature");
|
||||
assertEquals(QuantityType.valueOf(57.8, Units.PERCENT), condHandler.getHumidity(), "Humidity");
|
||||
assertEquals(QuantityType.valueOf(986.8, HECTO(SIUnits.PASCAL)), condHandler.getPressure(), "Pressure");
|
||||
assertEquals(QuantityType.valueOf(-1, HECTO(SIUnits.PASCAL)), condHandler.getPressureSea(), "Pressure Sea");
|
||||
} else {
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.internal.dto.SensorData;
|
||||
import org.openhab.binding.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.internal.util.FileReader;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.Constants;
|
||||
|
||||
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(2, valueArray.length, "Array size");
|
||||
|
||||
SensorData d = valueArray[0];
|
||||
// Assure latest data is taken
|
||||
String dateStr = d.getTimeStamp();
|
||||
if ("2020-06-09 06:38:08".equals(dateStr)) {
|
||||
// take newer one
|
||||
d = valueArray[1];
|
||||
}
|
||||
List<SensorDataValue> sensorDataVaueList = d.getSensorDataValues();
|
||||
assertNotNull(d);
|
||||
sensorDataVaueList.forEach(v -> {
|
||||
if (Constants.TEMPERATURE.equals(v.getValueType())) {
|
||||
assertEquals("22.70", v.getValue(), "Temperature");
|
||||
} else if (Constants.HUMIDITY.equals(v.getValueType())) {
|
||||
assertEquals("61.00", v.getValue(), "Humidity");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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(2, valueArray.length, "Array size");
|
||||
|
||||
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\""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.HTTPHandler;
|
||||
import org.openhab.binding.sensorcommunity.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();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
String conditionsStr = FileReader.readFileInString("src/test/resources/condition-result-no-pressure.json");
|
||||
assertNotNull(conditionsStr);
|
||||
Objects.requireNonNull(conditionsStr);
|
||||
conditions = http.getLatestValues(conditionsStr);
|
||||
|
||||
String particulateStr = FileReader.readFileInString("src/test/resources/pm-result.json");
|
||||
assertNotNull(particulateStr);
|
||||
Objects.requireNonNull(particulateStr);
|
||||
particulate = http.getLatestValues(particulateStr);
|
||||
|
||||
String noiseStr = FileReader.readFileInString("src/test/resources/noise-result.json");
|
||||
assertNotNull(noiseStr);
|
||||
Objects.requireNonNull(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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.internal.dto.SensorDataValue;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.HTTPHandler;
|
||||
import org.openhab.binding.sensorcommunity.internal.util.FileReader;
|
||||
import org.openhab.binding.sensorcommunity.internal.utils.Constants;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
Objects.requireNonNull(resource1);
|
||||
List<SensorDataValue> l = http.getLatestValues(resource1);
|
||||
assertNotNull(l);
|
||||
Objects.requireNonNull(l);
|
||||
l.forEach(sd -> {
|
||||
testSensorValue(sd);
|
||||
});
|
||||
|
||||
String resource2 = FileReader
|
||||
.readFileInString("src/test/resources/condition-result-no-pressure-flipped-values.json");
|
||||
assertNotNull(resource2);
|
||||
Objects.requireNonNull(resource2);
|
||||
l = http.getLatestValues(resource2);
|
||||
assertNotNull(l);
|
||||
Objects.requireNonNull(l);
|
||||
l.forEach(sd -> {
|
||||
testSensorValue(sd);
|
||||
});
|
||||
}
|
||||
|
||||
private void testSensorValue(SensorDataValue s) {
|
||||
if (s.getValueType().equals(Constants.TEMPERATURE)) {
|
||||
assertEquals("22.70", s.getValue(), "Temperature resource 1");
|
||||
} else if (s.getValueType().equals(Constants.HUMIDITY)) {
|
||||
assertEquals("61.00", s.getValue(), "Humidity resource 1");
|
||||
} else {
|
||||
assertTrue(false);
|
||||
}
|
||||
// System.out.println(s.getValue_type() + ":" + s.getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.BaseSensorHandler.UpdateStatus;
|
||||
import org.openhab.binding.sensorcommunity.internal.mock.NoiseHandlerExtension;
|
||||
import org.openhab.binding.sensorcommunity.internal.mock.ThingMock;
|
||||
import org.openhab.binding.sensorcommunity.internal.util.FileReader;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
|
||||
/**
|
||||
* 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(UpdateStatus.OK, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(51.0, Units.DECIBEL), noiseHandler.getNoiseEQCache(), "Noise EQ");
|
||||
assertEquals(QuantityType.valueOf(47.2, Units.DECIBEL), noiseHandler.getNoiseMinCache(), "Noise Min");
|
||||
assertEquals(QuantityType.valueOf(57.0, Units.DECIBEL), noiseHandler.getNoiseMaxCache(), "Noise Max");
|
||||
} 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(UpdateStatus.VALUE_ERROR, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(-1, Units.DECIBEL), noiseHandler.getNoiseEQCache(), "Values undefined");
|
||||
assertEquals(QuantityType.valueOf(-1, Units.DECIBEL), noiseHandler.getNoiseMinCache(), "Values undefined");
|
||||
assertEquals(QuantityType.valueOf(-1, Units.DECIBEL), noiseHandler.getNoiseMaxCache(), "Values undefined");
|
||||
} 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(UpdateStatus.VALUE_EMPTY, result, "Valid update");
|
||||
}
|
||||
|
||||
@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(UpdateStatus.CONNECTION_ERROR, result, "Valid update");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.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("1.95", Double.toString(d1r2), "Double 1.95, 2 places");
|
||||
// System.out.println("D1R2 " + d1r2);
|
||||
double d1r1 = NumberUtils.round(d1, 1);
|
||||
// System.out.println("D1R1 " + d1r1);
|
||||
assertEquals("2.0", Double.toString(d1r1), "Double 1.95, 1 place");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundingDown() {
|
||||
double d1 = 1.94;
|
||||
double d1r2 = NumberUtils.round(d1, 2);
|
||||
assertEquals("1.94", Double.toString(d1r2), "Double 1.94, 2 places");
|
||||
// System.out.println("D1R2 " + d1r2);
|
||||
double d1r1 = NumberUtils.round(d1, 1);
|
||||
// System.out.println("D1R1 " + d1r1);
|
||||
assertEquals("1.9", Double.toString(d1r1), "Double 1.94, 1 place");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringNumbers() {
|
||||
String d1 = "1.94";
|
||||
double d1r2 = NumberUtils.round(d1, 2);
|
||||
assertEquals("1.94", Double.toString(d1r2), "Double 1.94, 2 places");
|
||||
// System.out.println("D1R2 " + d1r2);
|
||||
double d1r1 = NumberUtils.round(d1, 1);
|
||||
// System.out.println("D1R1 " + d1r1);
|
||||
assertEquals("1.9", Double.toString(d1r1), "Double 1.94, 1 place");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.BaseSensorHandler.ConfigStatus;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.BaseSensorHandler.LifecycleStatus;
|
||||
import org.openhab.binding.sensorcommunity.internal.handler.BaseSensorHandler.UpdateStatus;
|
||||
import org.openhab.binding.sensorcommunity.internal.mock.PMHandlerExtension;
|
||||
import org.openhab.binding.sensorcommunity.internal.mock.ThingMock;
|
||||
import org.openhab.binding.sensorcommunity.internal.util.FileReader;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
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(ConfigStatus.EXTERNAL_SENSOR_OK, pmHandler.getConfigStatus(), "Handler Configuration status");
|
||||
}
|
||||
|
||||
@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(ConfigStatus.SENSOR_ID_NEGATIVE, pmHandler.getConfigStatus(), "Handler Configuration status");
|
||||
}
|
||||
|
||||
@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(UpdateStatus.OK, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(2.9, Units.MICROGRAM_PER_CUBICMETRE), pmHandler.getPM25Cache(), "PM25");
|
||||
assertEquals(QuantityType.valueOf(5.2, Units.MICROGRAM_PER_CUBICMETRE), pmHandler.getPM100Cache(), "PM100");
|
||||
} 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(UpdateStatus.VALUE_ERROR, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(-1, Units.MICROGRAM_PER_CUBICMETRE), pmHandler.getPM25Cache(),
|
||||
"Values undefined");
|
||||
assertEquals(QuantityType.valueOf(-1, Units.MICROGRAM_PER_CUBICMETRE), pmHandler.getPM100Cache(),
|
||||
"Values undefined");
|
||||
} 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(UpdateStatus.VALUE_EMPTY, result, "Valid update");
|
||||
}
|
||||
|
||||
@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("ipAdress", "192.168.178.1");
|
||||
t.setConfiguration(properties);
|
||||
|
||||
PMHandlerExtension pmHandler = new PMHandlerExtension(t);
|
||||
UpdateStatus result = pmHandler.updateChannels(null);
|
||||
assertEquals(UpdateStatus.CONNECTION_ERROR, result, "Valid update");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalPMSensor() {
|
||||
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/internal-data.json");
|
||||
if (pmJson != null) {
|
||||
UpdateStatus result = pmHandler.updateChannels("[" + pmJson + "]");
|
||||
assertEquals(UpdateStatus.OK, result, "Valid update");
|
||||
assertEquals(QuantityType.valueOf(4.3, Units.MICROGRAM_PER_CUBICMETRE), pmHandler.getPM25Cache(), "PM25");
|
||||
assertEquals(QuantityType.valueOf(10.5, Units.MICROGRAM_PER_CUBICMETRE), pmHandler.getPM100Cache(),
|
||||
"PM100");
|
||||
} else {
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.mock;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.mock;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.mock;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sensorcommunity.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.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("sensorcommunity", "test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThingTypeUID getThingTypeUID() {
|
||||
return new ThingTypeUID("sensorcommunity:any");
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.sensorcommunity.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(14, dt.getDayOfMonth(), "Day");
|
||||
assertEquals(8, dt.getMonthValue(), "Month");
|
||||
assertEquals(2020, dt.getYear(), "Year");
|
||||
|
||||
String s = dt.format(DateTimeUtils.DTF);
|
||||
assertEquals(jsonDateString, s, "String");
|
||||
} catch (DateTimeParseException e) {
|
||||
assertFalse(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.sensorcommunity.internal.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"software_version": "NRZ-2020-133",
|
||||
"age": "112",
|
||||
"sensordatavalues": [
|
||||
{
|
||||
"value_type": "SDS_P1",
|
||||
"value": "10.52"
|
||||
},
|
||||
{
|
||||
"value_type": "SDS_P2",
|
||||
"value": "4.32"
|
||||
},
|
||||
{
|
||||
"value_type": "BME280_temperature",
|
||||
"value": "17.59"
|
||||
},
|
||||
{
|
||||
"value_type": "BME280_pressure",
|
||||
"value": "98680.28"
|
||||
},
|
||||
{
|
||||
"value_type": "BME280_humidity",
|
||||
"value": "57.78"
|
||||
},
|
||||
{
|
||||
"value_type": "samples",
|
||||
"value": "5070500"
|
||||
},
|
||||
{
|
||||
"value_type": "min_micro",
|
||||
"value": "28"
|
||||
},
|
||||
{
|
||||
"value_type": "max_micro",
|
||||
"value": "20091"
|
||||
},
|
||||
{
|
||||
"value_type": "interval",
|
||||
"value": "145000"
|
||||
},
|
||||
{
|
||||
"value_type": "signal",
|
||||
"value": "-81"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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": "Sensor.Community",
|
||||
"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": "Sensor.Community",
|
||||
"name": "Laerm"
|
||||
},
|
||||
"pin": "15",
|
||||
"id": 39745
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user