added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.sensebox-${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-sensebox" description="Sensebox Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.sensebox/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal;
|
||||
|
||||
import static org.openhab.binding.sensebox.internal.SenseBoxBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxData;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxDescriptor;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxLoc;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxLocation;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxSensor;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.Version;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxAPIConnection} is responsible for fetching data from the senseBox API server.
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SenseBoxAPIConnection {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SenseBoxAPIConnection.class);
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
private static final Properties HEADERS = new Properties();
|
||||
|
||||
private static final String METHOD = "GET";
|
||||
|
||||
private static final int TIMEOUT = 30 * 1000; // 30 seconds
|
||||
|
||||
public SenseBoxAPIConnection() {
|
||||
Version version = FrameworkUtil.getBundle(this.getClass()).getVersion();
|
||||
HEADERS.put("User-Agent", "openHAB / senseBox binding " + version.toString());
|
||||
logger.trace("Headers: {}", HEADERS);
|
||||
}
|
||||
|
||||
public SenseBoxData reallyFetchDataFromServer(String senseBoxId) {
|
||||
String query = SENSEMAP_API_URL_BASE + "/boxes/" + senseBoxId;
|
||||
|
||||
// the caching layer does not like null values
|
||||
SenseBoxData result = new SenseBoxData();
|
||||
|
||||
try {
|
||||
String body = HttpUtil.executeUrl(METHOD, query, HEADERS, null, null, TIMEOUT);
|
||||
|
||||
logger.trace("Fetched Data: {}", body);
|
||||
SenseBoxData parsedData = gson.fromJson(body, SenseBoxData.class);
|
||||
|
||||
// Assume all is well at first
|
||||
parsedData.setStatus(ThingStatus.ONLINE);
|
||||
|
||||
// Could perhaps be simplified via triply-nested arrays
|
||||
// http://stackoverflow.com/questions/36946875/how-can-i-parse-geojson-with-gson
|
||||
for (SenseBoxLoc loc : parsedData.getLocs()) {
|
||||
if (loc.getGeometry() != null) {
|
||||
List<Double> locationData = loc.getGeometry().getData();
|
||||
if (locationData != null) {
|
||||
SenseBoxLocation location = new SenseBoxLocation();
|
||||
|
||||
if (locationData.size() > 0) {
|
||||
location.setLongitude(locationData.get(0));
|
||||
}
|
||||
|
||||
if (locationData.size() > 1) {
|
||||
location.setLatitude(locationData.get(1));
|
||||
}
|
||||
|
||||
if (locationData.size() > 2) {
|
||||
location.setHeight(locationData.get(2));
|
||||
}
|
||||
|
||||
parsedData.setLocation(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (SenseBoxSensor sensor : parsedData.getSensors()) {
|
||||
if ("VEML6070".equals(sensor.getSensorType())) {
|
||||
// "unit" is not nicely comparable, so use sensor type for now
|
||||
parsedData.setUvIntensity(sensor);
|
||||
} else if ("SDS 011".equals(sensor.getSensorType())) {
|
||||
// "unit" is not nicely comparable, neither is type, so use sensor title for now
|
||||
if ("PM2.5".equals(sensor.getTitle())) {
|
||||
parsedData.setParticulateMatter2dot5(sensor);
|
||||
} else if ("PM10".equals(sensor.getTitle())) {
|
||||
parsedData.setParticulateMatter10(sensor);
|
||||
} else {
|
||||
logger.debug("SDS 011 sensor title is {}", sensor.getTitle());
|
||||
}
|
||||
} else if ("lx".equals(sensor.getUnit())) {
|
||||
if (sensor.getLastMeasurement() != null) {
|
||||
if (!(INVALID_BRIGHTNESS.equals(sensor.getLastMeasurement().getValue()))) {
|
||||
parsedData.setLuminance(sensor);
|
||||
}
|
||||
}
|
||||
} else if ("Pa".equals(sensor.getUnit()) || "hPa".equals(sensor.getUnit())) {
|
||||
parsedData.setPressure(sensor);
|
||||
} else if ("%".equals(sensor.getUnit())) {
|
||||
parsedData.setHumidity(sensor);
|
||||
} else if ("°C".equals(sensor.getUnit())) {
|
||||
parsedData.setTemperature(sensor);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(" Sensor: {}", sensor);
|
||||
logger.debug(" Sensor unit: {}", sensor.getUnit());
|
||||
logger.debug(" Sensor type: {}", sensor.getSensorType());
|
||||
logger.debug(" Sensor LM: {}", sensor.getLastMeasurement());
|
||||
if (sensor.getLastMeasurement() != null) {
|
||||
logger.debug(" Sensor LM value: {}", sensor.getLastMeasurement().getValue());
|
||||
logger.debug(" Sensor LM date: '{}'", sensor.getLastMeasurement().getCreatedAt());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SenseBoxDescriptor descriptor = new SenseBoxDescriptor();
|
||||
descriptor.setApiUrl(query);
|
||||
String image = parsedData.getImage();
|
||||
if (image != null && !image.isEmpty()) {
|
||||
descriptor.setImageUrl(SENSEMAP_IMAGE_URL_BASE + "/" + image);
|
||||
}
|
||||
descriptor.setMapUrl(SENSEMAP_MAP_URL_BASE + "/explore/" + senseBoxId);
|
||||
parsedData.setDescriptor(descriptor);
|
||||
|
||||
logger.trace("=================================");
|
||||
|
||||
result = parsedData;
|
||||
} catch (IOException e) {
|
||||
logger.debug("IO problems while fetching data: {} / {}", query, e.getMessage());
|
||||
result.setStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SenseBoxBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "sensebox";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BOX = new ThingTypeUID(BINDING_ID, "box");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_LOCATION = "descriptors#location";
|
||||
|
||||
public static final String CHANNEL_UV_INTENSITY = "measurements#uvIntensity";
|
||||
public static final String CHANNEL_ILLUMINANCE = "measurements#illuminance";
|
||||
public static final String CHANNEL_PRESSURE = "measurements#pressure";
|
||||
public static final String CHANNEL_HUMIDITY = "measurements#humidity";
|
||||
public static final String CHANNEL_TEMPERATURE = "measurements#temperature";
|
||||
public static final String CHANNEL_PARTICULATE_MATTER_2_5 = "measurements#particulateMatter2dot5";
|
||||
public static final String CHANNEL_PARTICULATE_MATTER_10 = "measurements#particulateMatter10";
|
||||
|
||||
public static final String CHANNEL_UV_INTENSITY_LR = "lastReported#uvIntensityLastReported";
|
||||
public static final String CHANNEL_ILLUMINANCE_LR = "lastReported#illuminanceLastReported";
|
||||
public static final String CHANNEL_PRESSURE_LR = "lastReported#pressureLastReported";
|
||||
public static final String CHANNEL_HUMIDITY_LR = "lastReported#humidityLastReported";
|
||||
public static final String CHANNEL_TEMPERATURE_LR = "lastReported#temperatureLastReported";
|
||||
public static final String CHANNEL_PARTICULATE_MATTER_2_5_LR = "lastReported#particulateMatter2dot5LastReported";
|
||||
public static final String CHANNEL_PARTICULATE_MATTER_10_LR = "lastReported#particulateMatter10LastReported";
|
||||
|
||||
// List of all Property names
|
||||
public static final String PROPERTY_NAME = "Name";
|
||||
public static final String PROPERTY_EXPOSURE = "Exposure";
|
||||
public static final String PROPERTY_IMAGE_URL = "ImageUrl";
|
||||
public static final String PROPERTY_MAP_URL = "MapUrl";
|
||||
|
||||
// Base URL of the API server
|
||||
public static final String SENSEMAP_API_URL_BASE = "https://api.opensensemap.org";
|
||||
public static final String SENSEMAP_IMAGE_URL_BASE = "https://opensensemap.org/userimages";
|
||||
public static final String SENSEMAP_MAP_URL_BASE = "https://opensensemap.org";
|
||||
|
||||
// Minimum timeslice between API requests in seconds
|
||||
public static final int MINIMUM_UPDATE_INTERVAL = 5 * 60;
|
||||
|
||||
// How long do we want each cache entry to be available?
|
||||
public static final int CACHE_EXPIRY = 10 * 1000; // 10s
|
||||
|
||||
// 67108860 is an invalid reading which the API sends us nevertheless
|
||||
public static final String INVALID_BRIGHTNESS = "67108860";
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal;
|
||||
|
||||
import static org.openhab.binding.sensebox.internal.SenseBoxBindingConstants.THING_TYPE_BOX;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sensebox.internal.handler.SenseBoxHandler;
|
||||
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.Component;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.sensebox")
|
||||
@NonNullByDefault
|
||||
public class SenseBoxHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_BOX);
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_BOX)) {
|
||||
return new SenseBoxHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxConfiguration} is the base class for configuration
|
||||
* information held by devices and modules
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SenseBoxConfiguration {
|
||||
|
||||
private @Nullable String senseBoxId;
|
||||
private long refreshInterval = 300;
|
||||
|
||||
public long getRefreshInterval() {
|
||||
return refreshInterval;
|
||||
}
|
||||
|
||||
public void setRefreshInterval(long refreshInterval) {
|
||||
this.refreshInterval = refreshInterval;
|
||||
}
|
||||
|
||||
public @Nullable String getSenseBoxId() {
|
||||
return senseBoxId;
|
||||
}
|
||||
|
||||
public void setSenseBoxId(String senseBoxId) {
|
||||
this.senseBoxId = senseBoxId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxData} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxData {
|
||||
|
||||
@SerializedName("_id")
|
||||
private String id;
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
@SerializedName("exposure")
|
||||
private String exposure;
|
||||
|
||||
@SerializedName("image")
|
||||
private String image;
|
||||
|
||||
@SerializedName("loc")
|
||||
private List<SenseBoxLoc> locs;
|
||||
|
||||
@SerializedName("sensors")
|
||||
private List<SenseBoxSensor> sensors;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private ThingStatus status;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxDescriptor descriptor;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxLocation location;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor uvIntensity;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor luminance;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor pressure;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor humidity;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor temperature;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor particulateMatter2dot5;
|
||||
|
||||
@Expose(deserialize = false)
|
||||
private SenseBoxSensor particulateMatter10;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getExposure() {
|
||||
return exposure;
|
||||
}
|
||||
|
||||
public void setExposure(String exposure) {
|
||||
this.exposure = exposure;
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public SenseBoxDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public void setDescriptor(SenseBoxDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public SenseBoxLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(SenseBoxLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public List<SenseBoxLoc> getLocs() {
|
||||
return locs;
|
||||
}
|
||||
|
||||
public void setLocs(List<SenseBoxLoc> locs) {
|
||||
this.locs = locs;
|
||||
}
|
||||
|
||||
public List<SenseBoxSensor> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
|
||||
public void setSensors(List<SenseBoxSensor> sensors) {
|
||||
this.sensors = sensors;
|
||||
}
|
||||
|
||||
public ThingStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(ThingStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getUvIntensity() {
|
||||
return uvIntensity;
|
||||
}
|
||||
|
||||
public void setUvIntensity(SenseBoxSensor uvIntensity) {
|
||||
this.uvIntensity = uvIntensity;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getLuminance() {
|
||||
return luminance;
|
||||
}
|
||||
|
||||
public void setLuminance(SenseBoxSensor luminance) {
|
||||
this.luminance = luminance;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public void setPressure(SenseBoxSensor pressure) {
|
||||
this.pressure = pressure;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(SenseBoxSensor humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(SenseBoxSensor temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getParticulateMatter2dot5() {
|
||||
return particulateMatter2dot5;
|
||||
}
|
||||
|
||||
public void setParticulateMatter2dot5(SenseBoxSensor particulateMatter2dot5) {
|
||||
this.particulateMatter2dot5 = particulateMatter2dot5;
|
||||
}
|
||||
|
||||
public SenseBoxSensor getParticulateMatter10() {
|
||||
return particulateMatter10;
|
||||
}
|
||||
|
||||
public void setParticulateMatter10(SenseBoxSensor particulateMatter10) {
|
||||
this.particulateMatter10 = particulateMatter10;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxDescriptor} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxDescriptor {
|
||||
|
||||
private String apiUrl;
|
||||
|
||||
private String imageUrl;
|
||||
|
||||
private String mapUrl;
|
||||
|
||||
public String getApiUrl() {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
public void setApiUrl(String apiUrl) {
|
||||
this.apiUrl = apiUrl;
|
||||
}
|
||||
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
public String getMapUrl() {
|
||||
return mapUrl;
|
||||
}
|
||||
|
||||
public void setMapUrl(String mapUrl) {
|
||||
this.mapUrl = mapUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxGeometry} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxGeometry {
|
||||
|
||||
@SerializedName("coordinates")
|
||||
private List<Double> data;
|
||||
|
||||
public List<Double> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<Double> data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxLoc} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxLoc {
|
||||
|
||||
@SerializedName("geometry")
|
||||
private SenseBoxGeometry geometry;
|
||||
|
||||
public SenseBoxGeometry getGeometry() {
|
||||
return geometry;
|
||||
}
|
||||
|
||||
public void setGeometry(SenseBoxGeometry geometry) {
|
||||
this.geometry = geometry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxLocation} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxLocation {
|
||||
|
||||
private double latitude;
|
||||
|
||||
private double longitude;
|
||||
|
||||
private double height;
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public double getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(double height) {
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxMeasurement} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxMeasurement {
|
||||
|
||||
@SerializedName("value")
|
||||
private String value;
|
||||
|
||||
@SerializedName("createdAt")
|
||||
private String createdAt;
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(String createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxSensor} holds a de-serialized representation
|
||||
* of the API response and the data therein...
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
*/
|
||||
public class SenseBoxSensor {
|
||||
|
||||
@SerializedName("_id")
|
||||
private String id;
|
||||
|
||||
@SerializedName("title")
|
||||
private String title;
|
||||
|
||||
@SerializedName("unit")
|
||||
private String unit;
|
||||
|
||||
@SerializedName("icon")
|
||||
private String icon;
|
||||
|
||||
@SerializedName("sensorType")
|
||||
private String sensorType;
|
||||
|
||||
@SerializedName("lastMeasurement")
|
||||
private SenseBoxMeasurement lastMeasurement;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getUnit() {
|
||||
// the uom library uses the 'MICRO SIGN', so if we encounter the GREEK SMALL LETTER MU,
|
||||
// replace it with the proper representation.
|
||||
return unit != null ? unit.replaceAll("\u03bc", "\u00b5") : "";
|
||||
}
|
||||
|
||||
public void setUnit(String unit) {
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public String getSensorType() {
|
||||
return sensorType;
|
||||
}
|
||||
|
||||
public void setSensorType(String sensorType) {
|
||||
this.sensorType = sensorType;
|
||||
}
|
||||
|
||||
public SenseBoxMeasurement getLastMeasurement() {
|
||||
return lastMeasurement;
|
||||
}
|
||||
|
||||
public void setLastMeasurement(SenseBoxMeasurement lastMeasurement) {
|
||||
this.lastMeasurement = lastMeasurement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sensebox.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sensebox.internal.SenseBoxBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
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.sensebox.internal.SenseBoxAPIConnection;
|
||||
import org.openhab.binding.sensebox.internal.config.SenseBoxConfiguration;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxData;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxLocation;
|
||||
import org.openhab.binding.sensebox.internal.dto.SenseBoxSensor;
|
||||
import org.openhab.core.cache.ExpiringCacheMap;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.MetricPrefix;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
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.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SenseBoxHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Hakan Tandogan - Initial contribution
|
||||
* @author Hakan Tandogan - Ignore incorrect data for brightness readings
|
||||
* @author Hakan Tandogan - Changed use of caching utils to ESH ExpiringCacheMap
|
||||
* @author Hakan Tandogan - Unit of Measurement support
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SenseBoxHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SenseBoxHandler.class);
|
||||
|
||||
protected @NonNullByDefault({}) SenseBoxConfiguration thingConfiguration;
|
||||
|
||||
private @Nullable SenseBoxData data;
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
private static final BigDecimal ONEHUNDRED = BigDecimal.valueOf(100l);
|
||||
|
||||
private static final String CACHE_KEY_DATA = "DATA";
|
||||
|
||||
private final ExpiringCacheMap<String, SenseBoxData> cache = new ExpiringCacheMap<>(CACHE_EXPIRY);
|
||||
|
||||
private final SenseBoxAPIConnection connection = new SenseBoxAPIConnection();
|
||||
|
||||
public SenseBoxHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Start initializing!");
|
||||
|
||||
thingConfiguration = getConfigAs(SenseBoxConfiguration.class);
|
||||
|
||||
String senseBoxId = thingConfiguration.getSenseBoxId();
|
||||
logger.debug("Thing Configuration {} initialized {}", getThing().getUID(), senseBoxId);
|
||||
|
||||
String offlineReason = "";
|
||||
boolean validConfig = true;
|
||||
|
||||
if (senseBoxId == null || senseBoxId.trim().isEmpty()) {
|
||||
offlineReason = "senseBox ID is mandatory and must be configured";
|
||||
validConfig = false;
|
||||
}
|
||||
|
||||
if (thingConfiguration.getRefreshInterval() < MINIMUM_UPDATE_INTERVAL) {
|
||||
logger.warn("Refresh interval is much too small, setting to default of {} seconds",
|
||||
MINIMUM_UPDATE_INTERVAL);
|
||||
thingConfiguration.setRefreshInterval(MINIMUM_UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
if (senseBoxId != null && validConfig) {
|
||||
cache.put(CACHE_KEY_DATA, () -> {
|
||||
return connection.reallyFetchDataFromServer(senseBoxId);
|
||||
});
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
startAutomaticRefresh();
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, offlineReason);
|
||||
}
|
||||
logger.debug("Thing {} initialized {}", getThing().getUID(), getThing().getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
data = fetchData();
|
||||
if (data != null && ThingStatus.ONLINE == data.getStatus()) {
|
||||
publishDataForChannel(channelUID);
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
}
|
||||
} else {
|
||||
logger.debug("Unsupported command {}! Supported commands: REFRESH", command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopAutomaticRefresh();
|
||||
}
|
||||
|
||||
private void stopAutomaticRefresh() {
|
||||
if (refreshJob != null) {
|
||||
refreshJob.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishData() {
|
||||
logger.debug("Refreshing data for box {}, scheduled after {} seconds...", thingConfiguration.getSenseBoxId(),
|
||||
thingConfiguration.getRefreshInterval());
|
||||
data = fetchData();
|
||||
if (data != null && ThingStatus.ONLINE == data.getStatus()) {
|
||||
publishProperties();
|
||||
publishChannels();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
private void startAutomaticRefresh() {
|
||||
stopAutomaticRefresh();
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::publishData, 0, thingConfiguration.getRefreshInterval(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private @Nullable SenseBoxData fetchData() {
|
||||
return cache.get(CACHE_KEY_DATA);
|
||||
}
|
||||
|
||||
private void publishProperties() {
|
||||
SenseBoxData localData = data;
|
||||
if (localData != null) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(PROPERTY_NAME, localData.getName());
|
||||
properties.put(PROPERTY_EXPOSURE, localData.getExposure());
|
||||
properties.put(PROPERTY_IMAGE_URL, localData.getDescriptor().getImageUrl());
|
||||
properties.put(PROPERTY_MAP_URL, localData.getDescriptor().getMapUrl());
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishChannels() {
|
||||
thing.getChannels().forEach(channel -> publishDataForChannel(channel.getUID()));
|
||||
}
|
||||
|
||||
private void publishDataForChannel(ChannelUID channelUID) {
|
||||
SenseBoxData localData = data;
|
||||
if (localData != null && isLinked(channelUID)) {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_LOCATION:
|
||||
updateState(channelUID, locationFromData(localData.getLocation()));
|
||||
break;
|
||||
case CHANNEL_UV_INTENSITY:
|
||||
updateState(channelUID, decimalFromSensor(localData.getUvIntensity()));
|
||||
break;
|
||||
case CHANNEL_ILLUMINANCE:
|
||||
updateState(channelUID, decimalFromSensor(localData.getLuminance()));
|
||||
break;
|
||||
case CHANNEL_PRESSURE:
|
||||
updateState(channelUID, decimalFromSensor(localData.getPressure()));
|
||||
break;
|
||||
case CHANNEL_HUMIDITY:
|
||||
updateState(channelUID, decimalFromSensor(localData.getHumidity()));
|
||||
break;
|
||||
case CHANNEL_TEMPERATURE:
|
||||
updateState(channelUID, decimalFromSensor(localData.getTemperature()));
|
||||
break;
|
||||
case CHANNEL_PARTICULATE_MATTER_2_5:
|
||||
updateState(channelUID, decimalFromSensor(localData.getParticulateMatter2dot5()));
|
||||
break;
|
||||
case CHANNEL_PARTICULATE_MATTER_10:
|
||||
updateState(channelUID, decimalFromSensor(localData.getParticulateMatter10()));
|
||||
break;
|
||||
case CHANNEL_UV_INTENSITY_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getUvIntensity()));
|
||||
break;
|
||||
case CHANNEL_ILLUMINANCE_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getLuminance()));
|
||||
break;
|
||||
case CHANNEL_PRESSURE_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getPressure()));
|
||||
break;
|
||||
case CHANNEL_HUMIDITY_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getHumidity()));
|
||||
break;
|
||||
case CHANNEL_TEMPERATURE_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getTemperature()));
|
||||
break;
|
||||
case CHANNEL_PARTICULATE_MATTER_2_5_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getParticulateMatter2dot5()));
|
||||
break;
|
||||
case CHANNEL_PARTICULATE_MATTER_10_LR:
|
||||
updateState(channelUID, dateTimeFromSensor(localData.getParticulateMatter10()));
|
||||
break;
|
||||
default:
|
||||
logger.debug("Command received for an unknown channel: {}", channelUID.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private State dateTimeFromSensor(@Nullable SenseBoxSensor sensorData) {
|
||||
State result = UnDefType.UNDEF;
|
||||
if (sensorData != null && sensorData.getLastMeasurement() != null
|
||||
&& sensorData.getLastMeasurement().getCreatedAt() != null
|
||||
&& !sensorData.getLastMeasurement().getCreatedAt().isEmpty()) {
|
||||
result = new DateTimeType(sensorData.getLastMeasurement().getCreatedAt());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private State decimalFromSensor(@Nullable SenseBoxSensor sensorData) {
|
||||
State result = UnDefType.UNDEF;
|
||||
if (sensorData != null && sensorData.getLastMeasurement() != null
|
||||
&& sensorData.getLastMeasurement().getValue() != null
|
||||
&& !sensorData.getLastMeasurement().getValue().isEmpty()) {
|
||||
logger.debug("About to determine quantity for {} / {}", sensorData.getLastMeasurement().getValue(),
|
||||
sensorData.getUnit());
|
||||
BigDecimal bd = new BigDecimal(sensorData.getLastMeasurement().getValue());
|
||||
switch (sensorData.getUnit()) {
|
||||
case "%":
|
||||
result = new QuantityType<>(bd, SmartHomeUnits.PERCENT);
|
||||
break;
|
||||
case "°C":
|
||||
result = new QuantityType<>(bd, SIUnits.CELSIUS);
|
||||
break;
|
||||
case "Pa":
|
||||
result = new QuantityType<>(bd, SIUnits.PASCAL);
|
||||
break;
|
||||
case "hPa":
|
||||
if (BigDecimal.valueOf(10000l).compareTo(bd) < 0) {
|
||||
// Some stations report measurements in Pascal, but send 'hPa' as units...
|
||||
bd = bd.divide(ONEHUNDRED);
|
||||
}
|
||||
result = new QuantityType<>(bd, MetricPrefix.HECTO(SIUnits.PASCAL));
|
||||
break;
|
||||
case "lx":
|
||||
result = new QuantityType<>(bd, SmartHomeUnits.LUX);
|
||||
break;
|
||||
case "\u00b5g/m³":
|
||||
result = new QuantityType<>(bd, SmartHomeUnits.MICROGRAM_PER_CUBICMETRE);
|
||||
break;
|
||||
case "\u00b5W/cm²":
|
||||
result = new QuantityType<>(bd, SmartHomeUnits.MICROWATT_PER_SQUARE_CENTIMETRE);
|
||||
break;
|
||||
default:
|
||||
// The data provider might have configured some unknown unit, accept at least the
|
||||
// measurement
|
||||
logger.debug("Could not determine unit for '{}', using default", sensorData.getUnit());
|
||||
result = new QuantityType<>(bd, SmartHomeUnits.ONE);
|
||||
}
|
||||
logger.debug("State: '{}'", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private State locationFromData(@Nullable SenseBoxLocation locationData) {
|
||||
State result = UnDefType.UNDEF;
|
||||
if (locationData != null) {
|
||||
result = new PointType(new DecimalType(locationData.getLatitude()),
|
||||
new DecimalType(locationData.getLongitude()), new DecimalType(locationData.getHeight()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="sensebox" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>senseBox Binding</name>
|
||||
<description>The senseBox binding imports data from the senseBox Citizen Science project.</description>
|
||||
<author>Hakan Tandoğan</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:sensebox:config">
|
||||
<parameter name="senseBoxId" type="text" required="true">
|
||||
<label>Box ID</label>
|
||||
<description>Id of the box, can be found on the map details.</description>
|
||||
</parameter>
|
||||
<parameter name="refreshInterval" type="integer" min="300" max="86400" unit="s">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Refresh interval for senseBox data.</description>
|
||||
<default>300</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,51 @@
|
||||
# binding
|
||||
binding.sensebox.description = Das senseBox Binding importiert Daten aus dem senseBox Citizen Science-Projekt.
|
||||
|
||||
# thing types
|
||||
thing-type.sensebox.box.label = senseBox
|
||||
thing-type.sensebox.box.description = Ein senseBox Sensor.
|
||||
|
||||
# thing type config description
|
||||
thing-type.config.sensebox.sensor.senseBoxId.label = senseBox ID
|
||||
thing-type.config.sensebox.sensor.senseBoxId.description = Die ID des senseBox Sensors.
|
||||
thing-type.config.sensebox.sensor.refreshInterval.label = Abfrageintervall
|
||||
thing-type.config.sensebox.sensor.refreshInterval.description = Intervall zur Abfrage der senseBox Daten.
|
||||
|
||||
# channel group types
|
||||
channel-group-type.sensebox.descriptors.label = senseBox Beschreibung
|
||||
channel-group-type.sensebox.descriptors.description = Fasst Daten der senseBox zusammen.
|
||||
channel-group-type.sensebox.measurements.label = Messwerte
|
||||
channel-group-type.sensebox.measurements.description = Fasst Messwerte zusammen.
|
||||
channel-group-type.sensebox.lastReported.label = Letzte Messung
|
||||
channel-group-type.sensebox.lastReported.description = Fasst Zeitpunkt der Messwerte zusammen.
|
||||
|
||||
# channel types
|
||||
channel-type.sensebox.uvIntensity.label = UV-Intensität
|
||||
channel-type.sensebox.uvIntensity.description = Aktuelle UV-Intensität.
|
||||
channel-type.sensebox.uvIntensityLastReported.label = Letzte Messung UV-Intensität
|
||||
channel-type.sensebox.uvIntensityLastReported.description = Zeigt den Zeitpunkt der letzten Messung der UV-Intensität an.
|
||||
channel-type.sensebox.uvIntensityLastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.sensebox.illuminance.label = Beleuchtungsstärke
|
||||
channel-type.sensebox.illuminance.description = Aktuelle Beleuchtungsstärke.
|
||||
channel-type.sensebox.illuminanceLastReported.label = Letzte Messung Beleuchtungsstärke
|
||||
channel-type.sensebox.illuminanceLastReported.description = Zeigt den Zeitpunkt der letzten Messung der Beleuchtungsstärke an.
|
||||
channel-type.sensebox.illuminanceLastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.sensebox.pressureLastReported.label = Letzte Messung Luftdrucks
|
||||
channel-type.sensebox.pressureLastReported.description = Zeigt den Zeitpunkt der letzten Messung des Luftdrucks an.
|
||||
channel-type.sensebox.pressureLastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.sensebox.humidityLastReported.label = Letzte Messung Luftfeuchtigkeit
|
||||
channel-type.sensebox.humidityLastReported.description = Zeigt den Zeitpunkt der letzten Messung der Luftfeuchtigkeit an.
|
||||
channel-type.sensebox.humidityLastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.sensebox.temperatureLastReported.label = Letzte Messung Außentemperatur
|
||||
channel-type.sensebox.temperatureLastReported.description = Zeigt den Zeitpunkt der letzten Messung der Außentemperatur an.
|
||||
channel-type.sensebox.temperatureLastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.sensebox.particulateMatter2dot5.label = Feinstaub - PM2.5
|
||||
channel-type.sensebox.particulateMatter2dot5.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 2,5 µm.
|
||||
channel-type.sensebox.particulateMatter2dot5LastReported.label = Letzte Messung PM2.5
|
||||
channel-type.sensebox.particulateMatter2dot5LastReported.description = Zeigt den Zeitpunkt der letzten Messung von PM2.5 an.
|
||||
channel-type.sensebox.particulateMatter2dot5LastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.sensebox.particulateMatter10.label = Feinstaub - PM10
|
||||
channel-type.sensebox.particulateMatter10.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 10 µm.
|
||||
channel-type.sensebox.particulateMatter10LastReported.label = Letzte Messung PM10
|
||||
channel-type.sensebox.particulateMatter10LastReported.description = Zeigt den Zeitpunkt der letzten Messung von PM10 an.
|
||||
channel-type.sensebox.particulateMatter10LastReported.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sensebox"
|
||||
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">
|
||||
|
||||
<!-- This thing represents the Arduino box that sends data to api.opensensebox.org . -->
|
||||
<thing-type id="box">
|
||||
<label>senseBox</label>
|
||||
<description>This is a senseBox sensor.</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group typeId="descriptors" id="descriptors"/>
|
||||
<channel-group typeId="measurements" id="measurements"/>
|
||||
<channel-group typeId="lastReported" id="lastReported"/>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>senseBoxId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:sensebox:config"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sensebox"
|
||||
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">
|
||||
|
||||
<!-- Groups to better manage link display -->
|
||||
<channel-group-type id="descriptors">
|
||||
<label>Descriptors</label>
|
||||
<description>Box descriptors like Location, description, etc.</description>
|
||||
<channels>
|
||||
<channel id="location" typeId="system.location"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="measurements">
|
||||
<label>Measurements</label>
|
||||
<description>Measurements as fetched from the API.</description>
|
||||
<channels>
|
||||
<channel id="uvIntensity" typeId="uvIntensity"/>
|
||||
<channel id="illuminance" typeId="illuminance"/>
|
||||
<channel id="pressure" typeId="system.barometric-pressure"/>
|
||||
<channel id="humidity" typeId="system.atmospheric-humidity"/>
|
||||
<channel id="temperature" typeId="system.outdoor-temperature"/>
|
||||
<channel id="particulateMatter2dot5" typeId="particulateMatter2dot5"/>
|
||||
<channel id="particulateMatter10" typeId="particulateMatter10"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="lastReported">
|
||||
<label>Last Reported</label>
|
||||
<description>Timestamps when a measurement was last reported.</description>
|
||||
<channels>
|
||||
<channel id="uvIntensityLastReported" typeId="uvIntensityLastReported"/>
|
||||
<channel id="illuminanceLastReported" typeId="illuminanceLastReported"/>
|
||||
<channel id="pressureLastReported" typeId="pressureLastReported"/>
|
||||
<channel id="humidityLastReported" typeId="humidityLastReported"/>
|
||||
<channel id="temperatureLastReported" typeId="temperatureLastReported"/>
|
||||
<channel id="particulateMatter2dot5LastReported" typeId="particulateMatter2dot5LastReported"/>
|
||||
<channel id="particulateMatter10LastReported" typeId="particulateMatter10LastReported"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<!-- The channels themselves -->
|
||||
<!--
|
||||
"title": "UV-Intensität",
|
||||
"unit": "µW/cm²",
|
||||
"sensorType": "VEML6070",
|
||||
-->
|
||||
<channel-type id="uvIntensity">
|
||||
<item-type>Number:Intensity</item-type>
|
||||
<label>UV Intensity</label>
|
||||
<description>Current UV intensity.</description>
|
||||
<state readOnly="true" pattern="%.2f µW/cm²"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uvIntensityLastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>UV Intensity Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
"title": "Beleuchtungsstärke",
|
||||
"unit": "lx",
|
||||
"sensorType": "TSL45315",
|
||||
-->
|
||||
<channel-type id="illuminance">
|
||||
<item-type>Number:Illuminance</item-type>
|
||||
<label>Illuminance</label>
|
||||
<description>Current illuminance.</description>
|
||||
<state readOnly="true" pattern="%.2f lx"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="illuminanceLastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Illuminance Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
"title": "Luftdruck",
|
||||
"unit": "hPa",
|
||||
"sensorType": "BMP280",
|
||||
-->
|
||||
<channel-type id="pressureLastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Pressure Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
"title": "rel. Luftfeuchte",
|
||||
"unit": "%",
|
||||
"sensorType": "HDC1008",
|
||||
-->
|
||||
<channel-type id="humidityLastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Humidity Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
"title": "Temperatur",
|
||||
"unit": "°C",
|
||||
"sensorType": "HDC1008",
|
||||
-->
|
||||
<channel-type id="temperatureLastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Temperature Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
"title": "PM2.5",
|
||||
"unit": "µg/m³",
|
||||
"sensorType": "SDS 011",
|
||||
-->
|
||||
<channel-type id="particulateMatter2dot5">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Particulate Matter - PM2.5</label>
|
||||
<description>Current density of particles less than 2.5 µm in diameter.</description>
|
||||
<state readOnly="true" pattern="%.2f µg/m³">
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="particulateMatter2dot5LastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Particulate Matter 2.5 Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
"title": "PM10",
|
||||
"unit": "µg/m³",
|
||||
"sensorType": "SDS 011",
|
||||
-->
|
||||
<channel-type id="particulateMatter10">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Particulate Matter - PM10</label>
|
||||
<description>Current density of particles less than 10 µm in diameter.</description>
|
||||
<state readOnly="true" pattern="%.2f µg/m³">
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="particulateMatter10LastReported" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Particulate Matter 10 Measurement Time</label>
|
||||
<description>Timestamp when data was measured.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user