[wundergroundupdatereceiver] Initial contribution (#10105)
* [wundergroundupdatereceiver] Initial implementation Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Code review Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Fix some description formatting Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Add some more channel types per request Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Add more headers to response Signed-off-by: Daniel Demus <daniel-github@demus.dk> Based on the observed headers from actual traffic to wunderground.com. * [wundergroundupdatereceiver] Discovery service Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Upgrade to 3.2, fix group name constants Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Add a list of channel types Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Add dateutc as synthetic DateTime channel Also add som emore constants Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Do more programmatic configuration Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] More readme Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Update copyright year Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Handle multiple instance request parameters Signed-off-by: Daniel Demus <daniel-github@demus.dk> Ie. those that can have an index number in the name, fx. temp1f, temp2f * [wundergroundupdatereceiver] Add unmapped but mappable channels To support multiple devices any new parameters that are submitted cause a new channel to be created Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Don't pass superfluous config to channels Also documentation additions Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Add generated i18n file Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Re-case test method names Signed-off-by: Daniel Demus <daniel-github@demus.dk> * [wundergroundupdatereceiver] Re-word thing file section of README Signed-off-by: Daniel Demus <daniel-github@demus.dk> Co-authored-by: Daniel Demus <dde@nine.dk>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.wundergroundupdatereceiver-${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-wundergroundupdatereceiver" description="Wunderground Update Receiver Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.wundergroundupdatereceiver/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static org.openhab.core.library.unit.SIUnits.METRE;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.measure.Unit;
|
||||
import javax.measure.quantity.Length;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.DefaultSystemChannelTypeProvider;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
import tech.units.indriya.format.SimpleUnitFormat;
|
||||
import tech.units.indriya.function.MultiplyConverter;
|
||||
import tech.units.indriya.unit.TransformedUnit;
|
||||
|
||||
/**
|
||||
* The {@link WundergroundUpdateReceiverBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "wundergroundupdatereceiver";
|
||||
|
||||
public static final String STATION_ID_PARAMETER = "ID";
|
||||
public static final String REPRESENTATION_PROPERTY = "stationId";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_UPDATE_RECEIVER = new ThingTypeUID(BINDING_ID,
|
||||
"wundergroundUpdateReceiver");
|
||||
static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_UPDATE_RECEIVER);
|
||||
|
||||
public static final String NOW = "now";
|
||||
|
||||
// Excluded technical paramter names
|
||||
public static final String REALTIME_MARKER = "realtime";
|
||||
public static final String PASSWORD = "PASSWORD";
|
||||
public static final String ACTION = "action";
|
||||
|
||||
// List of default synthetic channeltypes added to a new thing
|
||||
public static final String DATEUTC_DATETIME = "dateutc-datetime";
|
||||
public static final String LAST_RECEIVED_DATETIME = "last-received-datetime";
|
||||
public static final String LAST_RECEIVED = "last-received";
|
||||
public static final String LAST_QUERY = "last-query";
|
||||
public static final String LAST_QUERY_STATE = LAST_QUERY + "-state";
|
||||
public static final String LAST_QUERY_TRIGGER = LAST_QUERY + "-trigger";
|
||||
|
||||
// Channel groups
|
||||
public static final String METADATA_GROUP = "metadata";
|
||||
public static final String WIND_GROUP = "wind";
|
||||
public static final String TEMPERATURE_GROUP = "temperature";
|
||||
public static final String HUMIDITY_GROUP = "humidity";
|
||||
public static final String RAIN_GROUP = "rain";
|
||||
public static final String SUNLIGHT_GROUP = "sunlight";
|
||||
public static final String PRESSURE_GROUP = "pressure";
|
||||
public static final String POLLUTION_GROUP = "pollution";
|
||||
|
||||
// Known or observed request paramters received from weather stations submitting to wunderground.com
|
||||
public static final String DATEUTC = "dateutc";
|
||||
public static final String SOFTWARE_TYPE = "softwaretype";
|
||||
public static final String LOW_BATTERY = "lowbatt";
|
||||
public static final String REALTIME_FREQUENCY = "rtfreq";
|
||||
public static final String WIND_DIRECTION = "winddir";
|
||||
public static final String WIND_SPEED = "windspeedmph";
|
||||
public static final String GUST_SPEED = "windgustmph";
|
||||
public static final String GUST_DIRECTION = "windgustdir";
|
||||
public static final String WIND_SPEED_AVG_2MIN = "windspdmph_avg2m";
|
||||
public static final String WIND_DIRECTION_AVG_2MIN = "winddir_avg2m";
|
||||
public static final String GUST_SPEED_AVG_10MIN = "windgustmph_10m";
|
||||
public static final String GUST_DIRECTION_AVG_10MIN = "windgustdir_10m";
|
||||
public static final String TEMPERATURE = "tempf";
|
||||
public static final String TEMPERATURE_INDEXED = "^temp(\\d+)f$";
|
||||
public static final String WIND_CHILL = "windchillf";
|
||||
public static final String INDOOR_TEMPERATURE = "indoortempf";
|
||||
public static final String SOIL_TEMPERATURE = "soiltempf";
|
||||
public static final String SOIL_TEMPERATURE_INDEXED = "^soiltemp(\\d+)f$";
|
||||
public static final String HUMIDITY = "humidity";
|
||||
public static final String INDOOR_HUMIDITY = "indoorhumidity";
|
||||
public static final String DEWPOINT = "dewptf";
|
||||
public static final String SOIL_MOISTURE = "soilmoisture";
|
||||
public static final String SOIL_MOISTURE_INDEXED = "^soilmoisture(\\d+)$";
|
||||
public static final String LEAF_WETNESS = "leafwetness";
|
||||
public static final String LEAF_WETNESS_INDEXED = "^leafwetness(\\d+)$";
|
||||
public static final String RAIN_IN = "rainin";
|
||||
public static final String DAILY_RAIN_IN = "dailyrainin";
|
||||
public static final String WEEKLY_RAIN_IN = "weeklyrainin";
|
||||
public static final String MONTHLY_RAIN_IN = "monthlyrainin";
|
||||
public static final String YEARLY_RAIN_IN = "yearlyrainin";
|
||||
public static final String SOLAR_RADIATION = "solarradiation";
|
||||
public static final String UV = "UV";
|
||||
public static final String VISIBILITY = "visibility";
|
||||
public static final String WEATHER = "weather";
|
||||
public static final String CLOUDS = "clouds";
|
||||
public static final String BAROM_IN = "baromin";
|
||||
public static final String AQ_NO = "AqNO";
|
||||
public static final String AQ_NO2T = "AqNO2T";
|
||||
public static final String AQ_NO2 = "AqNO2";
|
||||
public static final String AQ_NO2Y = "AqNO2Y";
|
||||
public static final String AQ_NOX = "AqNOX";
|
||||
public static final String AQ_NOY = "AqNOY";
|
||||
public static final String AQ_NO3 = "AqNO3";
|
||||
public static final String AQ_SO4 = "AqSO4";
|
||||
public static final String AQ_SO2 = "AqSO2";
|
||||
public static final String AQ_SO2T = "AqSO2T";
|
||||
public static final String AQ_CO = "AqCO";
|
||||
public static final String AQ_COT = "AqCOT";
|
||||
public static final String AQ_EC = "AqEC";
|
||||
public static final String AQ_OC = "AqOC";
|
||||
public static final String AQ_BC = "AqBC";
|
||||
public static final String AQ_UV_AETH = "AqUV-AETH";
|
||||
public static final String AQ_PM2_5 = "AqPM2.5";
|
||||
public static final String AQ_PM10 = "AqPM10";
|
||||
public static final String AQ_OZONE = "AqOZONE";
|
||||
|
||||
public static final ChannelTypeUID LAST_RECEIVED_DATETIME_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
LAST_RECEIVED_DATETIME);
|
||||
public static final ChannelTypeUID LAST_QUERY_STATE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
LAST_QUERY_STATE);
|
||||
public static final ChannelTypeUID LAST_QUERY_TRIGGER_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
LAST_QUERY_TRIGGER);
|
||||
public static final ChannelTypeUID DATEUTC_DATETIME_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
DATEUTC_DATETIME);
|
||||
public static final ChannelTypeUID DATEUTC_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, DATEUTC);
|
||||
public static final ChannelTypeUID LOW_BATTERY_CHANNELTYPEUID = DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_LOW_BATTERY
|
||||
.getUID();
|
||||
public static final ChannelTypeUID SOFTWARETYPE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "softwaretype");
|
||||
public static final ChannelTypeUID REALTIME_FREQUENCY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"realtime-frequency");
|
||||
public static final ChannelTypeUID WIND_SPEED_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "wind-speed");
|
||||
public static final ChannelTypeUID WIND_DIRECTION_CHANNELTYPEUID = DefaultSystemChannelTypeProvider.SYSTEM_WIND_DIRECTION
|
||||
.getUID();
|
||||
public static final ChannelTypeUID GUST_SPEED_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "wind-gust-speed");
|
||||
public static final ChannelTypeUID GUST_DIRECTION_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"wind-gust-direction");
|
||||
public static final ChannelTypeUID WIND_SPEED_AVG_2MIN_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"wind-speed-avg-2min");
|
||||
public static final ChannelTypeUID WIND_DIRECTION_AVG_2MIN_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"wind-direction-avg-2min");
|
||||
public static final ChannelTypeUID GUST_SPEED_10MIN_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"wind-gust-speed-10min");
|
||||
public static final ChannelTypeUID GUST_DIRECTION_10MIN_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"wind-gust-direction-10min");
|
||||
public static final ChannelTypeUID TEMPERATURE_CHANNELTYPEUID = DefaultSystemChannelTypeProvider.SYSTEM_OUTDOOR_TEMPERATURE
|
||||
.getUID();
|
||||
public static final ChannelTypeUID HUMIDITY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "humidity");
|
||||
public static final ChannelTypeUID INDOOR_HUMIDITY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"indoor-humidity");
|
||||
public static final ChannelTypeUID DEW_POINT_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "dew-point");
|
||||
public static final ChannelTypeUID WIND_CHILL_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "wind-chill");
|
||||
// for extra outdoor sensors use temp2f, temp3f, and so on
|
||||
public static final ChannelTypeUID INDOOR_TEMPERATURE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"indoor-temperature");
|
||||
// for sensors 2,3,4 use soiltemp2f, soiltemp3f, and soiltemp4f
|
||||
public static final ChannelTypeUID SOIL_TEMPERATURE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"soil-temperature");
|
||||
public static final ChannelTypeUID RAIN_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "rain");
|
||||
public static final ChannelTypeUID RAIN_DAILY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "rain-daily");
|
||||
public static final ChannelTypeUID RAIN_WEEKLY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "rain-weekly");
|
||||
public static final ChannelTypeUID RAIN_MONTHLY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "rain-monthly");
|
||||
public static final ChannelTypeUID RAIN_YEARLY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "rain-yearly");
|
||||
public static final ChannelTypeUID METAR_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "metar");
|
||||
public static final ChannelTypeUID CLOUDS_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "clouds");
|
||||
// for sensors 2,3,4 use soilmoisture2, soilmoisture3, and soilmoisture4
|
||||
public static final ChannelTypeUID SOIL_MOISTURE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "soil-moisture");
|
||||
// for sensor 2 use leafwetness2
|
||||
public static final ChannelTypeUID LEAFWETNESS_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "leafwetness");
|
||||
public static final ChannelTypeUID SOLARRADIATION_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "solarradiation");
|
||||
public static final ChannelTypeUID UV_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "uv");
|
||||
public static final ChannelTypeUID VISIBILITY_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "visibility");
|
||||
public static final ChannelTypeUID BAROMETRIC_PRESSURE_CHANNELTYPEUID = DefaultSystemChannelTypeProvider.SYSTEM_BAROMETRIC_PRESSURE
|
||||
.getUID();
|
||||
public static final ChannelTypeUID NITRIC_OXIDE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "nitric-oxide");
|
||||
public static final ChannelTypeUID NITROGEN_DIOXIDE_MEASURED_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"nitrogen-dioxide-measured");
|
||||
public static final ChannelTypeUID NITROGEN_DIOXIDE_NOX_NO_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"nitrogen-dioxide-nox-no");
|
||||
public static final ChannelTypeUID NITROGEN_DIOXIDE_NOY_NO_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"nitrogen-dioxide-noy-no");
|
||||
public static final ChannelTypeUID NITROGEN_OXIDES_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"nitrogen-oxides");
|
||||
public static final ChannelTypeUID TOTAL_REACTIVE_NITROGEN_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"total-reactive-nitrogen");
|
||||
public static final ChannelTypeUID NO3_ION_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "no3-ion");
|
||||
public static final ChannelTypeUID SO4_ION_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "so4-ion");
|
||||
public static final ChannelTypeUID SULFUR_DIOXIDE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "sulfur-dioxide");
|
||||
public static final ChannelTypeUID SULFUR_DIOXIDE_TRACE_LEVELS_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"sulfur-dioxide-trace-levels");
|
||||
public static final ChannelTypeUID CARBON_MONOXIDE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"carbon-monoxide");
|
||||
public static final ChannelTypeUID CARBON_MONOXIDE_TRACE_LEVELS_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"carbon-monoxide-trace-levels");
|
||||
public static final ChannelTypeUID ELEMENTAL_CARBON_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID,
|
||||
"elemental-carbon");
|
||||
public static final ChannelTypeUID ORGANIC_CARBON_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "organic-carbon");
|
||||
public static final ChannelTypeUID BLACK_CARBON_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "black-carbon");
|
||||
public static final ChannelTypeUID AETHALOMETER_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "aethalometer");
|
||||
public static final ChannelTypeUID PM2_5_MASS_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "pm2_5-mass");
|
||||
public static final ChannelTypeUID PM10_MASS_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "pm10-mass");
|
||||
public static final ChannelTypeUID OZONE_CHANNELTYPEUID = new ChannelTypeUID(BINDING_ID, "ozone");
|
||||
|
||||
public static final Unit<Length> NAUTICAL_MILE = addUnit(
|
||||
new TransformedUnit<>("NM", METRE, MultiplyConverter.of(1852.0)));
|
||||
|
||||
static {
|
||||
SimpleUnitFormat.getInstance().label(NAUTICAL_MILE, "NM");
|
||||
}
|
||||
|
||||
private static <U extends Unit<?>> U addUnit(U unit) {
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link WundergroundUpdateReceiverConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverConfiguration {
|
||||
|
||||
/**
|
||||
* The station id as registered by wunderground.com or any string if not forwarding data to wunderground.com.
|
||||
* This value will be used as the representation property.
|
||||
*/
|
||||
public String stationId = "";
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Modified;
|
||||
|
||||
/**
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { DiscoveryService.class,
|
||||
WundergroundUpdateReceiverDiscoveryService.class }, configurationPid = "discovery.wundergroundupdatereceiver")
|
||||
public class WundergroundUpdateReceiverDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
@Nullable
|
||||
WundergroundUpdateReceiverServletControls servletControls;
|
||||
|
||||
private static final int TIMEOUT_SEC = 1;
|
||||
private final HashMap<String, Map<String, String[]>> thinglessStationIds = new HashMap<>();
|
||||
private boolean servletWasInactive = false;
|
||||
|
||||
private boolean scanning = false;
|
||||
|
||||
@Activate
|
||||
public WundergroundUpdateReceiverDiscoveryService() throws IllegalArgumentException {
|
||||
this(true);
|
||||
}
|
||||
|
||||
public WundergroundUpdateReceiverDiscoveryService(boolean useBackgroundDiscovery) throws IllegalArgumentException {
|
||||
super(WundergroundUpdateReceiverBindingConstants.SUPPORTED_THING_TYPES_UIDS, TIMEOUT_SEC,
|
||||
useBackgroundDiscovery);
|
||||
}
|
||||
|
||||
public void removeUnhandledStationId(String stationId) {
|
||||
thinglessStationIds.remove(stationId);
|
||||
}
|
||||
|
||||
public void addUnhandledStationId(@Nullable String stationId, Map<String, String[]> request) {
|
||||
if (stationId == null || stationId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!this.thinglessStationIds.containsKey(stationId)) {
|
||||
this.thinglessStationIds.put(stationId, request);
|
||||
if (isBackgroundDiscoveryEnabled()) {
|
||||
createDiscoveryResult(stationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDiscovering() {
|
||||
return isBackgroundDiscoveryEnabled() || isScanning();
|
||||
}
|
||||
|
||||
public @Nullable Map<String, String[]> getUnhandledStationRequest(@Nullable String stationId) {
|
||||
return this.thinglessStationIds.get(stationId);
|
||||
}
|
||||
|
||||
private void createDiscoveryResult(String stationId) {
|
||||
ThingUID id = new ThingUID(WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER, stationId);
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(id)
|
||||
.withRepresentationProperty(WundergroundUpdateReceiverBindingConstants.REPRESENTATION_PROPERTY)
|
||||
.withProperty(WundergroundUpdateReceiverBindingConstants.REPRESENTATION_PROPERTY, stationId)
|
||||
.withThingType(WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER)
|
||||
.withLabel("WundergroundUpdateReceiver ID " + stationId).build();
|
||||
this.thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Activate
|
||||
protected void activate(@Nullable Map<String, Object> configProperties) {
|
||||
super.activate(configProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modified
|
||||
protected void modified(@Nullable Map<String, Object> configProperties) {
|
||||
super.modified(configProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
setScanning(true);
|
||||
if (servletControls != null && !servletControls.isActive()) {
|
||||
servletWasInactive = true;
|
||||
servletControls.activate();
|
||||
}
|
||||
thinglessStationIds.keySet().forEach(this::createDiscoveryResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
super.stopScan();
|
||||
thinglessStationIds.keySet().forEach(this::createDiscoveryResult);
|
||||
if (!isBackgroundDiscoveryEnabled() && servletControls != null && servletWasInactive) {
|
||||
servletControls.deactivate();
|
||||
}
|
||||
setScanning(false);
|
||||
}
|
||||
|
||||
protected synchronized boolean isScanning() {
|
||||
return this.scanning;
|
||||
}
|
||||
|
||||
protected synchronized void setScanning(boolean value) {
|
||||
this.scanning = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.*;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.measure.Quantity;
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelGroupUID;
|
||||
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.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link WundergroundUpdateReceiverHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverHandler extends BaseThingHandler {
|
||||
|
||||
public String getStationId() {
|
||||
return config.stationId;
|
||||
}
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(WundergroundUpdateReceiverHandler.class);
|
||||
private final WundergroundUpdateReceiverServlet wundergroundUpdateReceiverServlet;
|
||||
private final WundergroundUpdateReceiverDiscoveryService discoveryService;
|
||||
private final WundergroundUpdateReceiverUnknownChannelTypeProvider channelTypeProvider;
|
||||
private final ChannelTypeRegistry channelTypeRegistry;
|
||||
|
||||
private final ChannelUID dateutcDatetimeChannel;
|
||||
private final ChannelUID lastReceivedChannel;
|
||||
private final ChannelUID queryStateChannel;
|
||||
private final ChannelUID queryTriggerChannel;
|
||||
|
||||
private WundergroundUpdateReceiverConfiguration config = new WundergroundUpdateReceiverConfiguration();
|
||||
|
||||
public WundergroundUpdateReceiverHandler(Thing thing,
|
||||
WundergroundUpdateReceiverServlet wunderGroundUpdateReceiverServlet,
|
||||
WundergroundUpdateReceiverDiscoveryService discoveryService,
|
||||
WundergroundUpdateReceiverUnknownChannelTypeProvider channelTypeProvider,
|
||||
ChannelTypeRegistry channelTypeRegistry) {
|
||||
super(thing);
|
||||
this.discoveryService = discoveryService;
|
||||
this.channelTypeProvider = channelTypeProvider;
|
||||
this.channelTypeRegistry = channelTypeRegistry;
|
||||
|
||||
final ChannelGroupUID metadatGroupUID = new ChannelGroupUID(getThing().getUID(), METADATA_GROUP);
|
||||
|
||||
this.dateutcDatetimeChannel = new ChannelUID(metadatGroupUID, DATEUTC_DATETIME);
|
||||
this.lastReceivedChannel = new ChannelUID(metadatGroupUID, LAST_RECEIVED);
|
||||
this.queryTriggerChannel = new ChannelUID(metadatGroupUID, LAST_QUERY_TRIGGER);
|
||||
this.queryStateChannel = new ChannelUID(metadatGroupUID, LAST_QUERY_STATE);
|
||||
|
||||
this.wundergroundUpdateReceiverServlet = Objects.requireNonNull(wunderGroundUpdateReceiverServlet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.trace("Ignoring command {}", command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
super.handleConfigurationUpdate(configurationParameters);
|
||||
this.wundergroundUpdateReceiverServlet.handlerConfigUpdated(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
this.config = getConfigAs(WundergroundUpdateReceiverConfiguration.class);
|
||||
wundergroundUpdateReceiverServlet.addHandler(this);
|
||||
@Nullable
|
||||
Map<String, String[]> requestParameters = discoveryService.getUnhandledStationRequest(config.stationId);
|
||||
if (requestParameters != null && thing.getChannels().isEmpty()) {
|
||||
final String[] noValues = new String[0];
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
List.of(LAST_RECEIVED, LAST_QUERY_TRIGGER, DATEUTC_DATETIME, LAST_QUERY_STATE)
|
||||
.forEach((String channelId) -> buildChannel(thingBuilder, channelId, noValues));
|
||||
requestParameters
|
||||
.forEach((String parameter, String[] query) -> buildChannel(thingBuilder, parameter, query));
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
discoveryService.removeUnhandledStationId(config.stationId);
|
||||
if (wundergroundUpdateReceiverServlet.isActive()) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
logger.debug("Wunderground update receiver listening for updates to station id {}", config.stationId);
|
||||
return;
|
||||
}
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
|
||||
wundergroundUpdateReceiverServlet.getErrorDetail());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
wundergroundUpdateReceiverServlet.removeHandler(this.getStationId());
|
||||
super.dispose();
|
||||
logger.debug("Wunderground update receiver stopped listening for updates to station id {}", config.stationId);
|
||||
}
|
||||
|
||||
public void updateChannelStates(Map<String, String> requestParameters) {
|
||||
requestParameters.forEach(this::updateChannelState);
|
||||
updateState(lastReceivedChannel, new DateTimeType());
|
||||
updateState(dateutcDatetimeChannel, safeResolvUtcDateTime(requestParameters.getOrDefault(DATEUTC, NOW)));
|
||||
String lastQuery = requestParameters.getOrDefault(LAST_QUERY, "");
|
||||
if (lastQuery.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
updateState(queryStateChannel, StringType.valueOf(lastQuery));
|
||||
triggerChannel(queryTriggerChannel, lastQuery);
|
||||
}
|
||||
|
||||
private void buildChannel(ThingBuilder thingBuilder, String parameter, String... query) {
|
||||
@Nullable
|
||||
WundergroundUpdateReceiverParameterMapping channelTypeMapping = WundergroundUpdateReceiverParameterMapping
|
||||
.getOrCreateMapping(parameter, String.join("", query), channelTypeProvider);
|
||||
if (channelTypeMapping == null) {
|
||||
return;
|
||||
}
|
||||
ChannelType channelType = channelTypeRegistry.getChannelType(channelTypeMapping.channelTypeId);
|
||||
if (channelType == null) {
|
||||
return;
|
||||
}
|
||||
ChannelBuilder channelBuilder = ChannelBuilder
|
||||
.create(new ChannelUID(thing.getUID(), channelTypeMapping.channelGroup, parameter))
|
||||
.withType(channelTypeMapping.channelTypeId).withAcceptedItemType(channelType.getItemType());
|
||||
thingBuilder.withChannel(channelBuilder.build());
|
||||
}
|
||||
|
||||
private DateTimeType safeResolvUtcDateTime(String dateUtc) {
|
||||
if (!dateUtc.isEmpty() && !NOW.equals(dateUtc)) {
|
||||
try {
|
||||
// Supposedly the format is "yyyy-MM-dd hh:mm:ss" from the weather station
|
||||
return new DateTimeType(ZonedDateTime.parse(dateUtc.replace(" ", "T") + "Z"));
|
||||
} catch (Exception ex) {
|
||||
logger.warn("The weather station is submitting unparsable datetime values: {}", dateUtc);
|
||||
}
|
||||
}
|
||||
return new DateTimeType();
|
||||
}
|
||||
|
||||
public void updateChannelState(String channelId, String[] stateParts) {
|
||||
updateChannelState(channelId, String.join("", stateParts));
|
||||
}
|
||||
|
||||
public void updateChannelState(String parameterName, String state) {
|
||||
Optional<Channel> channel = getThing().getChannels().stream()
|
||||
.filter(ch -> parameterName.equals(ch.getUID().getIdWithoutGroup())).findFirst();
|
||||
if (channel.isPresent()) {
|
||||
ChannelUID channelUID = channel.get().getUID();
|
||||
@Nullable
|
||||
Float numberValue = null;
|
||||
try {
|
||||
numberValue = Float.valueOf(state);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
|
||||
if (numberValue == null) {
|
||||
updateState(channelUID, StringType.valueOf(state));
|
||||
return;
|
||||
}
|
||||
@Nullable
|
||||
Unit<? extends Quantity<?>> unit = WundergroundUpdateReceiverParameterMapping.getUnit(parameterName);
|
||||
if (unit != null) {
|
||||
updateState(channelUID, new QuantityType<>(numberValue, unit));
|
||||
} else if (LOW_BATTERY.equals(parameterName)) {
|
||||
updateState(channelUID, OnOffType.from(state));
|
||||
} else {
|
||||
updateState(channelUID, new DecimalType(numberValue));
|
||||
}
|
||||
} else if (this.discoveryService.isDiscovering()
|
||||
&& !WundergroundUpdateReceiverParameterMapping.isExcluded(parameterName)) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
buildChannel(thingBuilder, parameterName, state);
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
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.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.http.HttpService;
|
||||
|
||||
/**
|
||||
* The {@link WundergroundUpdateReceiverHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.wundergroundupdatereceiver", service = ThingHandlerFactory.class)
|
||||
public class WundergroundUpdateReceiverHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final WundergroundUpdateReceiverDiscoveryService discoveryService;
|
||||
private final ChannelTypeRegistry channelTypeRegistry;
|
||||
private final WundergroundUpdateReceiverUnknownChannelTypeProvider channelTypeProvider;
|
||||
private final WundergroundUpdateReceiverServlet wunderGroundUpdateReceiverServlet;
|
||||
|
||||
@Activate
|
||||
public WundergroundUpdateReceiverHandlerFactory(@Reference HttpService httpService,
|
||||
@Reference WundergroundUpdateReceiverDiscoveryService discoveryService,
|
||||
@Reference WundergroundUpdateReceiverUnknownChannelTypeProvider channelTypeProvider,
|
||||
@Reference ChannelTypeRegistry channelTypeRegistry) {
|
||||
this.discoveryService = discoveryService;
|
||||
this.channelTypeRegistry = channelTypeRegistry;
|
||||
this.channelTypeProvider = channelTypeProvider;
|
||||
this.wunderGroundUpdateReceiverServlet = new WundergroundUpdateReceiverServlet(httpService,
|
||||
this.discoveryService);
|
||||
this.discoveryService.servletControls = this.wunderGroundUpdateReceiverServlet;
|
||||
if (this.discoveryService.isBackgroundDiscoveryEnabled()) {
|
||||
this.wunderGroundUpdateReceiverServlet.activate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return WundergroundUpdateReceiverBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_UPDATE_RECEIVER.equals(thingTypeUID)) {
|
||||
return new WundergroundUpdateReceiverHandler(thing, this.wunderGroundUpdateReceiverServlet,
|
||||
this.discoveryService, this.channelTypeProvider, this.channelTypeRegistry);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate(ComponentContext componentContext) {
|
||||
this.wunderGroundUpdateReceiverServlet.deactivate();
|
||||
this.wunderGroundUpdateReceiverServlet.dispose();
|
||||
super.deactivate(componentContext);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.ImperialUnits.*;
|
||||
import static org.openhab.core.library.unit.Units.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.measure.Quantity;
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
/**
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverParameterMapping {
|
||||
|
||||
public final String parameterName;
|
||||
public final ChannelTypeUID channelTypeId;
|
||||
public final String channelGroup;
|
||||
public final @Nullable Unit<? extends Quantity<?>> unit;
|
||||
public final boolean isIndexable;
|
||||
|
||||
public final @Nullable Pattern pattern;
|
||||
|
||||
private WundergroundUpdateReceiverParameterMapping(String parameterName, ChannelTypeUID channelTypeId,
|
||||
String channelGroup, @Nullable Unit<? extends Quantity<?>> unit, boolean isIndexable,
|
||||
@Nullable Pattern pattern) {
|
||||
this.parameterName = parameterName;
|
||||
this.channelTypeId = channelTypeId;
|
||||
this.channelGroup = channelGroup;
|
||||
this.unit = unit;
|
||||
this.isIndexable = isIndexable;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
private static final List<String> UNMAPPED_PARAMETERS = List.of(STATION_ID_PARAMETER, PASSWORD, ACTION,
|
||||
REALTIME_MARKER);
|
||||
|
||||
private static final WundergroundUpdateReceiverParameterMapping[] KNOWN_MAPPINGS = {
|
||||
new WundergroundUpdateReceiverParameterMapping(LAST_RECEIVED, LAST_RECEIVED_DATETIME_CHANNELTYPEUID,
|
||||
METADATA_GROUP, null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(LAST_QUERY_STATE, LAST_QUERY_STATE_CHANNELTYPEUID,
|
||||
METADATA_GROUP, null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(LAST_QUERY_TRIGGER, LAST_QUERY_TRIGGER_CHANNELTYPEUID,
|
||||
METADATA_GROUP, null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(DATEUTC_DATETIME, DATEUTC_DATETIME_CHANNELTYPEUID,
|
||||
METADATA_GROUP, null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(DATEUTC, DATEUTC_CHANNELTYPEUID, METADATA_GROUP, null, false,
|
||||
null),
|
||||
new WundergroundUpdateReceiverParameterMapping(SOFTWARE_TYPE, SOFTWARETYPE_CHANNELTYPEUID, METADATA_GROUP,
|
||||
null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(LOW_BATTERY, LOW_BATTERY_CHANNELTYPEUID, METADATA_GROUP,
|
||||
null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(REALTIME_FREQUENCY, REALTIME_FREQUENCY_CHANNELTYPEUID,
|
||||
METADATA_GROUP, null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(WIND_DIRECTION, WIND_DIRECTION_CHANNELTYPEUID, WIND_GROUP,
|
||||
DEGREE_ANGLE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(WIND_SPEED, WIND_SPEED_CHANNELTYPEUID, WIND_GROUP,
|
||||
MILES_PER_HOUR, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(GUST_SPEED, GUST_SPEED_CHANNELTYPEUID, WIND_GROUP,
|
||||
MILES_PER_HOUR, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(GUST_DIRECTION, GUST_DIRECTION_CHANNELTYPEUID, WIND_GROUP,
|
||||
DEGREE_ANGLE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(WIND_SPEED_AVG_2MIN, WIND_SPEED_AVG_2MIN_CHANNELTYPEUID,
|
||||
WIND_GROUP, MILES_PER_HOUR, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(WIND_DIRECTION_AVG_2MIN,
|
||||
WIND_DIRECTION_AVG_2MIN_CHANNELTYPEUID, WIND_GROUP, DEGREE_ANGLE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(GUST_SPEED_AVG_10MIN, GUST_SPEED_10MIN_CHANNELTYPEUID,
|
||||
WIND_GROUP, MILES_PER_HOUR, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(GUST_DIRECTION_AVG_10MIN,
|
||||
GUST_DIRECTION_10MIN_CHANNELTYPEUID, WIND_GROUP, DEGREE_ANGLE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(TEMPERATURE, TEMPERATURE_CHANNELTYPEUID, TEMPERATURE_GROUP,
|
||||
FAHRENHEIT, true, Pattern.compile(TEMPERATURE_INDEXED)),
|
||||
new WundergroundUpdateReceiverParameterMapping(INDOOR_TEMPERATURE, INDOOR_TEMPERATURE_CHANNELTYPEUID,
|
||||
TEMPERATURE_GROUP, FAHRENHEIT, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(SOIL_TEMPERATURE, SOIL_TEMPERATURE_CHANNELTYPEUID,
|
||||
TEMPERATURE_GROUP, FAHRENHEIT, true, Pattern.compile(SOIL_TEMPERATURE_INDEXED)),
|
||||
new WundergroundUpdateReceiverParameterMapping(WIND_CHILL, WIND_CHILL_CHANNELTYPEUID, TEMPERATURE_GROUP,
|
||||
FAHRENHEIT, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(HUMIDITY, HUMIDITY_CHANNELTYPEUID, HUMIDITY_GROUP, PERCENT,
|
||||
false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(INDOOR_HUMIDITY, INDOOR_HUMIDITY_CHANNELTYPEUID,
|
||||
HUMIDITY_GROUP, PERCENT, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(DEWPOINT, DEW_POINT_CHANNELTYPEUID, HUMIDITY_GROUP,
|
||||
FAHRENHEIT, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(SOIL_MOISTURE, SOIL_MOISTURE_CHANNELTYPEUID, HUMIDITY_GROUP,
|
||||
PERCENT, true, Pattern.compile(SOIL_MOISTURE_INDEXED)),
|
||||
new WundergroundUpdateReceiverParameterMapping(LEAF_WETNESS, LEAFWETNESS_CHANNELTYPEUID, HUMIDITY_GROUP,
|
||||
PERCENT, true, Pattern.compile(LEAF_WETNESS_INDEXED)),
|
||||
new WundergroundUpdateReceiverParameterMapping(RAIN_IN, RAIN_CHANNELTYPEUID, RAIN_GROUP, INCH, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(DAILY_RAIN_IN, RAIN_DAILY_CHANNELTYPEUID, RAIN_GROUP, INCH,
|
||||
false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(WEEKLY_RAIN_IN, RAIN_WEEKLY_CHANNELTYPEUID, RAIN_GROUP, INCH,
|
||||
false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(MONTHLY_RAIN_IN, RAIN_MONTHLY_CHANNELTYPEUID, RAIN_GROUP,
|
||||
INCH, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(YEARLY_RAIN_IN, RAIN_YEARLY_CHANNELTYPEUID, RAIN_GROUP, INCH,
|
||||
false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(SOLAR_RADIATION, SOLARRADIATION_CHANNELTYPEUID,
|
||||
SUNLIGHT_GROUP, IRRADIANCE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(UV, UV_CHANNELTYPEUID, SUNLIGHT_GROUP, null, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(VISIBILITY, VISIBILITY_CHANNELTYPEUID, SUNLIGHT_GROUP,
|
||||
NAUTICAL_MILE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(WEATHER, METAR_CHANNELTYPEUID, SUNLIGHT_GROUP, null, false,
|
||||
null),
|
||||
new WundergroundUpdateReceiverParameterMapping(CLOUDS, CLOUDS_CHANNELTYPEUID, SUNLIGHT_GROUP, null, false,
|
||||
null),
|
||||
new WundergroundUpdateReceiverParameterMapping(BAROM_IN, BAROMETRIC_PRESSURE_CHANNELTYPEUID, PRESSURE_GROUP,
|
||||
INCH_OF_MERCURY, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NO, NITRIC_OXIDE_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NO2, NITROGEN_DIOXIDE_NOX_NO_CHANNELTYPEUID,
|
||||
POLLUTION_GROUP, PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NO2T, NITROGEN_DIOXIDE_MEASURED_CHANNELTYPEUID,
|
||||
POLLUTION_GROUP, PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NO2Y, NITROGEN_DIOXIDE_NOY_NO_CHANNELTYPEUID,
|
||||
POLLUTION_GROUP, PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NOX, NITROGEN_OXIDES_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NOY, TOTAL_REACTIVE_NITROGEN_CHANNELTYPEUID,
|
||||
POLLUTION_GROUP, PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_NO3, NO3_ION_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_SO2, SULFUR_DIOXIDE_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_SO2T, SULFUR_DIOXIDE_TRACE_LEVELS_CHANNELTYPEUID,
|
||||
POLLUTION_GROUP, PARTS_PER_BILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_SO4, SO4_ION_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_CO, CARBON_MONOXIDE_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
PARTS_PER_MILLION, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_COT, CARBON_MONOXIDE_TRACE_LEVELS_CHANNELTYPEUID,
|
||||
POLLUTION_GROUP, MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_EC, ELEMENTAL_CARBON_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_OC, ORGANIC_CARBON_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_BC, BLACK_CARBON_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_UV_AETH, AETHALOMETER_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_PM2_5, PM2_5_MASS_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_PM10, PM10_MASS_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
MICROGRAM_PER_CUBICMETRE, false, null),
|
||||
new WundergroundUpdateReceiverParameterMapping(AQ_OZONE, OZONE_CHANNELTYPEUID, POLLUTION_GROUP,
|
||||
PARTS_PER_BILLION, false, null) };
|
||||
|
||||
public static @Nullable WundergroundUpdateReceiverParameterMapping getOrCreateMapping(String parameterName,
|
||||
String value, WundergroundUpdateReceiverUnknownChannelTypeProvider channelTypeProvider) {
|
||||
if (isExcluded(parameterName)) {
|
||||
return null;
|
||||
}
|
||||
Optional<WundergroundUpdateReceiverParameterMapping> knownMapping = lookupMapping(parameterName);
|
||||
return knownMapping.orElseGet(() -> new WundergroundUpdateReceiverParameterMapping(parameterName,
|
||||
channelTypeProvider.getOrCreateChannelType(parameterName, value).getUID(), "Uncategorized", null, false,
|
||||
null));
|
||||
}
|
||||
|
||||
public static boolean isExcluded(String parameter) {
|
||||
return UNMAPPED_PARAMETERS.contains(parameter);
|
||||
}
|
||||
|
||||
public static @Nullable Unit<? extends Quantity<?>> getUnit(String parameterName) {
|
||||
Optional<WundergroundUpdateReceiverParameterMapping> mapping = lookupMapping(parameterName);
|
||||
return mapping
|
||||
.<Unit<? extends Quantity<?>>> map(
|
||||
wundergroundUpdateReceiverParameterMapping -> wundergroundUpdateReceiverParameterMapping.unit)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static Optional<WundergroundUpdateReceiverParameterMapping> lookupMapping(String parameterName) {
|
||||
return Arrays.stream(KNOWN_MAPPINGS)
|
||||
.filter((WundergroundUpdateReceiverParameterMapping m) -> m.parameterName.equals(parameterName)
|
||||
|| (m.isIndexable && m.pattern != null && m.pattern.matcher(parameterName).matches()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.profiles.ProfileAdvisor;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.SystemProfiles;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link WundergroundUpdateReceiverProfileAdvisor} suggests the default profile for
|
||||
* all channels except last updated.
|
||||
*
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@Component
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverProfileAdvisor implements ProfileAdvisor {
|
||||
|
||||
@Override
|
||||
public @Nullable ProfileTypeUID getSuggestedProfileTypeUID(Channel channel, @Nullable String itemType) {
|
||||
return getSuggestedProfileTypeUID(channel.getChannelTypeUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ProfileTypeUID getSuggestedProfileTypeUID(ChannelType channelType, @Nullable String itemType) {
|
||||
return getSuggestedProfileTypeUID(channelType.getUID());
|
||||
}
|
||||
|
||||
private @Nullable ProfileTypeUID getSuggestedProfileTypeUID(@Nullable ChannelTypeUID channelTypeUID) {
|
||||
if (channelTypeUID == null || !channelTypeUID.getBindingId().equals(BINDING_ID)) {
|
||||
return null;
|
||||
}
|
||||
if (LAST_RECEIVED_DATETIME_CHANNELTYPEUID.equals(channelTypeUID)) {
|
||||
return SystemProfiles.TIMESTAMP_UPDATE;
|
||||
}
|
||||
return SystemProfiles.DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.io.http.servlet.BaseOpenHABServlet;
|
||||
import org.osgi.service.http.HttpContext;
|
||||
import org.osgi.service.http.HttpService;
|
||||
import org.osgi.service.http.NamespaceException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link WundergroundUpdateReceiverServlet} is responsible for receiving updates,and
|
||||
* updating the matching channels.
|
||||
*
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverServlet extends BaseOpenHABServlet
|
||||
implements WundergroundUpdateReceiverServletControls {
|
||||
|
||||
public static final String SERVLET_URL = "/weatherstation/updateweatherstation.php";
|
||||
private static final long serialVersionUID = -5296703727081438023L;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(WundergroundUpdateReceiverServlet.class);
|
||||
private final Map<String, WundergroundUpdateReceiverHandler> handlers = new HashMap<>();
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
private final WundergroundUpdateReceiverDiscoveryService discoveryService;
|
||||
|
||||
private boolean active = false;
|
||||
private String errorDetail = "";
|
||||
|
||||
public WundergroundUpdateReceiverServlet(HttpService httpService,
|
||||
WundergroundUpdateReceiverDiscoveryService discoveryService) {
|
||||
super(httpService);
|
||||
this.discoveryService = discoveryService;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
synchronized (LOCK) {
|
||||
return this.active;
|
||||
}
|
||||
}
|
||||
|
||||
public String getErrorDetail() {
|
||||
synchronized (LOCK) {
|
||||
return this.errorDetail;
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getStationIds() {
|
||||
return this.handlers.keySet();
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
activate(SERVLET_URL, httpService.createDefaultHttpContext());
|
||||
}
|
||||
|
||||
public void addHandler(WundergroundUpdateReceiverHandler handler) {
|
||||
synchronized (this.handlers) {
|
||||
if (this.handlers.containsKey(handler.getStationId())) {
|
||||
errorDetail = "Handler handling request for stationId " + handler.getStationId() + " is already added";
|
||||
logger.warn("Error during handler registration - StationId {} already being handled",
|
||||
handler.getStationId());
|
||||
return;
|
||||
}
|
||||
this.handlers.put(handler.getStationId(), handler);
|
||||
errorDetail = "";
|
||||
if (!isActive()) {
|
||||
activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeHandler(String stationId) {
|
||||
synchronized (this.handlers) {
|
||||
WundergroundUpdateReceiverHandler handler = this.handlers.get(stationId);
|
||||
if (handler != null) {
|
||||
this.handlers.remove(stationId);
|
||||
}
|
||||
if (this.handlers.isEmpty() && !this.discoveryService.isBackgroundDiscoveryEnabled()) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
synchronized (LOCK) {
|
||||
logger.debug("Stopping servlet {} at {}", getClass().getSimpleName(), SERVLET_URL);
|
||||
try {
|
||||
super.deactivate(SERVLET_URL);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// SERVLET_URL is already unregistered
|
||||
}
|
||||
errorDetail = "";
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void handlerConfigUpdated(WundergroundUpdateReceiverHandler handler) {
|
||||
synchronized (this.handlers) {
|
||||
final Set<Map.Entry<String, WundergroundUpdateReceiverHandler>> changedStationIds = this.handlers.entrySet()
|
||||
.stream().filter(entry -> handler.getThing().getUID().equals(entry.getValue().getThing().getUID()))
|
||||
.collect(toSet());
|
||||
changedStationIds.forEach(entry -> {
|
||||
logger.debug("Re-assigning listener from station id {} to station id {}", entry.getKey(),
|
||||
handler.getStationId());
|
||||
this.removeHandler(entry.getKey());
|
||||
this.addHandler(handler);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
synchronized (this.handlers) {
|
||||
Set<String> stationIds = new HashSet<>(getStationIds());
|
||||
stationIds.forEach(this::removeHandler);
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(String alias, HttpContext httpContext) {
|
||||
synchronized (LOCK) {
|
||||
try {
|
||||
logger.debug("Starting servlet {} at {}", getClass().getSimpleName(), alias);
|
||||
Dictionary<String, String> props = new Hashtable<>(1, 10);
|
||||
httpService.registerServlet(alias, this, props, httpContext);
|
||||
errorDetail = "";
|
||||
active = true;
|
||||
} catch (NamespaceException e) {
|
||||
active = false;
|
||||
errorDetail = "Servlet couldn't be registered - alias " + alias + " already in use";
|
||||
logger.warn("Error during servlet registration - alias {} already in use", alias, e);
|
||||
} catch (ServletException e) {
|
||||
active = false;
|
||||
errorDetail = "Servlet couldn't be registered - " + e.getMessage();
|
||||
logger.warn("Error during servlet registration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(@Nullable HttpServletRequest req, @Nullable HttpServletResponse resp) throws IOException {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
if (req == null) {
|
||||
return;
|
||||
}
|
||||
if (resp == null) {
|
||||
return;
|
||||
}
|
||||
if (req.getRequestURI() == null) {
|
||||
return;
|
||||
}
|
||||
logger.trace("doGet {}", req.getQueryString());
|
||||
|
||||
String stationId = req.getParameter(STATION_ID_PARAMETER);
|
||||
Optional.ofNullable(this.handlers.get(stationId)).ifPresentOrElse(handler -> {
|
||||
Map<String, String> states = req.getParameterMap().entrySet().stream()
|
||||
.collect(toMap(Map.Entry::getKey, e -> String.join("", e.getValue())));
|
||||
String queryString = req.getQueryString();
|
||||
if (queryString != null && queryString.length() > 0) {
|
||||
states.put(LAST_QUERY, queryString);
|
||||
}
|
||||
handler.updateChannelStates(states);
|
||||
}, () -> {
|
||||
this.discoveryService.addUnhandledStationId(stationId, req.getParameterMap());
|
||||
});
|
||||
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
resp.setContentType("text/html;charset=utf-8");
|
||||
resp.setContentLength(7);
|
||||
resp.setDateHeader("Date", Instant.now().toEpochMilli());
|
||||
resp.setHeader("Connection", "close");
|
||||
PrintWriter writer = resp.getWriter();
|
||||
writer.write("success");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
protected Map<String, WundergroundUpdateReceiverHandler> getHandlers() {
|
||||
return Collections.unmodifiableMap(this.handlers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface WundergroundUpdateReceiverServletControls {
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
boolean isActive();
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.wundergroundupdatereceiver.internal;
|
||||
|
||||
import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeProvider;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Daniel Demus - Initial contribution
|
||||
*/
|
||||
@Component(service = { ChannelTypeProvider.class, WundergroundUpdateReceiverUnknownChannelTypeProvider.class })
|
||||
@NonNullByDefault
|
||||
public class WundergroundUpdateReceiverUnknownChannelTypeProvider implements ChannelTypeProvider {
|
||||
|
||||
private static final List<String> BOOLEAN_STRINGS = List.of("1", "0", "true", "false");
|
||||
private final Map<ChannelTypeUID, ChannelType> channelTypes = new ConcurrentHashMap<>();
|
||||
private final Logger logger = LoggerFactory.getLogger(WundergroundUpdateReceiverUnknownChannelTypeProvider.class);
|
||||
|
||||
@Override
|
||||
public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
|
||||
return channelTypes.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
|
||||
return channelTypes.get(channelTypeUID);
|
||||
}
|
||||
|
||||
public ChannelType getOrCreateChannelType(String parameterName, String value) {
|
||||
ChannelTypeUID typeUid = new ChannelTypeUID(THING_TYPE_UPDATE_RECEIVER.getBindingId(), parameterName);
|
||||
@Nullable
|
||||
ChannelType type = getChannelType(typeUid, null);
|
||||
if (type == null) {
|
||||
String itemType = guessItemType(value);
|
||||
type = ChannelTypeBuilder.state(typeUid, parameterName + " channel type", itemType).build();
|
||||
return addChannelType(typeUid, type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static String guessItemType(String value) {
|
||||
if (BOOLEAN_STRINGS.contains(value.toLowerCase())) {
|
||||
return "Switch";
|
||||
}
|
||||
try {
|
||||
Float.valueOf(value);
|
||||
return "Number";
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
return "String";
|
||||
}
|
||||
|
||||
private ChannelType addChannelType(ChannelTypeUID channelTypeUID, ChannelType channelType) {
|
||||
logger.warn("Adding channelType {} for unknown parameter", channelTypeUID.getAsString());
|
||||
this.channelTypes.put(channelTypeUID, channelType);
|
||||
return channelType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="wundergroundupdatereceiver" 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>Wunderground Update Receiver Binding</name>
|
||||
<description>
|
||||
This binding enables acting as a receiver of updates from weather stations that post measurements to
|
||||
https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php.
|
||||
</description>
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,140 @@
|
||||
# binding
|
||||
|
||||
binding.wundergroundupdatereceiver.name = Wunderground Update Receiver Binding
|
||||
binding.wundergroundupdatereceiver.description = This binding enables acting as a receiver of updates from weather stations that post measurements to https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php.
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.wundergroundupdatereceiver.wundergroundUpdateReceiver.label = Update Receiver
|
||||
thing-type.wundergroundupdatereceiver.wundergroundUpdateReceiver.description = An endpoint thing that can receive and propagate HTTP GET updates meant for a particular station id at wunderground.com
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.wundergroundupdatereceiver.wundergroundUpdateReceiver.stationId.label = Station ID
|
||||
thing-type.config.wundergroundupdatereceiver.wundergroundUpdateReceiver.stationId.description = <br /> The wunderground.com update api requires a station id, that is defined for the WeatherUnderground account measurements are to be submitted to.<br /> <br /> In this binding it is used to identify a unique thing, so each weather-station or other apparatus submitting measurements can have a separate id, but if you don't intend to forward the observations to wunderground.com, this value can be any non-blank string.
|
||||
|
||||
# channel group types
|
||||
|
||||
channel-group-type.wundergroundupdatereceiver.humidity-group.label = Moisture
|
||||
channel-group-type.wundergroundupdatereceiver.humidity-group.description = Moisture measurements
|
||||
channel-group-type.wundergroundupdatereceiver.metadata-group.label = Metadata
|
||||
channel-group-type.wundergroundupdatereceiver.metadata-group.description = Metadata regarding the last submission
|
||||
channel-group-type.wundergroundupdatereceiver.pollution-group.label = Pollution
|
||||
channel-group-type.wundergroundupdatereceiver.pollution-group.description = Pollutant measurements
|
||||
channel-group-type.wundergroundupdatereceiver.pressure-group.label = Pressure
|
||||
channel-group-type.wundergroundupdatereceiver.pressure-group.description = Barometric measurements
|
||||
channel-group-type.wundergroundupdatereceiver.rain-group.label = Rain
|
||||
channel-group-type.wundergroundupdatereceiver.rain-group.description = Rain measurements
|
||||
channel-group-type.wundergroundupdatereceiver.sunlight-group.label = Sunlight
|
||||
channel-group-type.wundergroundupdatereceiver.sunlight-group.description = Sunlight measurements
|
||||
channel-group-type.wundergroundupdatereceiver.temperature-group.label = Temperature
|
||||
channel-group-type.wundergroundupdatereceiver.temperature-group.description = Temperature measurements
|
||||
channel-group-type.wundergroundupdatereceiver.wind-group.label = Wind
|
||||
channel-group-type.wundergroundupdatereceiver.wind-group.description = Wind measurements
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.wundergroundupdatereceiver.aethalometer.label = Second Channel of Aethalometer
|
||||
channel-type.wundergroundupdatereceiver.aethalometer.description = second channel of Aethalometer at 370 nm, µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.black-carbon.label = Black Carbon
|
||||
channel-type.wundergroundupdatereceiver.black-carbon.description = Black Carbon at 880 nm, µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.carbon-monoxide-trace-levels.label = Carbon Monoxide Trace Levels
|
||||
channel-type.wundergroundupdatereceiver.carbon-monoxide-trace-levels.description = Carbon Monoxide, trace levels ppb.
|
||||
channel-type.wundergroundupdatereceiver.carbon-monoxide.label = Carbon Monoxide
|
||||
channel-type.wundergroundupdatereceiver.carbon-monoxide.description = Carbon Monoxide, conventional ppm.
|
||||
channel-type.wundergroundupdatereceiver.clouds.label = Cloud Cover
|
||||
channel-type.wundergroundupdatereceiver.clouds.description = METAR style cloud cover.
|
||||
channel-type.wundergroundupdatereceiver.dateutc-datetime.label = Last Updated as DateTime
|
||||
channel-type.wundergroundupdatereceiver.dateutc-datetime.description = The date and time of the last update in UTC as submitted by the weather station converted to a DateTime value. In case of 'now', the current time is used.
|
||||
channel-type.wundergroundupdatereceiver.dateutc-datetime.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS
|
||||
channel-type.wundergroundupdatereceiver.dateutc.label = Last Updated
|
||||
channel-type.wundergroundupdatereceiver.dateutc.description = The date and time of the last update in UTC as submitted by the weather station. This can be 'now'.
|
||||
channel-type.wundergroundupdatereceiver.dew-point.label = Dew Point
|
||||
channel-type.wundergroundupdatereceiver.dew-point.description = Outdoor dew point.
|
||||
channel-type.wundergroundupdatereceiver.elemental-carbon.label = Elemental Carbon
|
||||
channel-type.wundergroundupdatereceiver.elemental-carbon.description = Elemental Carbon, PM2.5 µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.humidity.label = Humidity
|
||||
channel-type.wundergroundupdatereceiver.humidity.description = Humidity in %.
|
||||
channel-type.wundergroundupdatereceiver.indoor-humidity.label = Indoor Humidity
|
||||
channel-type.wundergroundupdatereceiver.indoor-humidity.description = Indoor humidity in %.
|
||||
channel-type.wundergroundupdatereceiver.indoor-temperature.label = Indoor Temperature
|
||||
channel-type.wundergroundupdatereceiver.indoor-temperature.description = Indoor temperature.
|
||||
channel-type.wundergroundupdatereceiver.last-query-state.label = The last query
|
||||
channel-type.wundergroundupdatereceiver.last-query-state.description = The part of the last query after the first unurlencoded '?'
|
||||
channel-type.wundergroundupdatereceiver.last-query-trigger.label = The last query
|
||||
channel-type.wundergroundupdatereceiver.last-query-trigger.description = The part of the last query after the first unurlencoded '?'
|
||||
channel-type.wundergroundupdatereceiver.last-received-datetime.label = Last Received
|
||||
channel-type.wundergroundupdatereceiver.last-received-datetime.description = The date and time of the last update.
|
||||
channel-type.wundergroundupdatereceiver.last-received-datetime.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS
|
||||
channel-type.wundergroundupdatereceiver.leafwetness.label = Leaf Wetness
|
||||
channel-type.wundergroundupdatereceiver.leafwetness.description = Leaf wetness in %.
|
||||
channel-type.wundergroundupdatereceiver.metar.label = METAR Weather Report
|
||||
channel-type.wundergroundupdatereceiver.metar.description = METAR formatted weather report
|
||||
channel-type.wundergroundupdatereceiver.nitric-oxide.label = Nitric Oxide
|
||||
channel-type.wundergroundupdatereceiver.nitric-oxide.description = Nitric Oxide ppm.
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-measured.label = Nitrogen Dioxide
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-measured.description = Nitrogen Dioxide, true measure ppb.
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-nox-no.label = NO2 X computed
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-nox-no.description = NO2 computed, NOx-NO ppb.
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-noy-no.label = NO2 Y computed, NOy-NO ppb
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-noy-no.description = NO2 computed, NOy-NO ppb.
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-oxides.label = Nitrogen Oxides
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-oxides.description = Nitrogen Oxides ppb.
|
||||
channel-type.wundergroundupdatereceiver.no3-ion.label = NO3 ion
|
||||
channel-type.wundergroundupdatereceiver.no3-ion.description = NO3 ion (nitrate, not adjusted for ammonium ion) µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.organic-carbon.label = Organic Carbon
|
||||
channel-type.wundergroundupdatereceiver.organic-carbon.description = Organic Carbon, not adjusted for oxygen and hydrogen, PM2.5 µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.ozone.label = Ozone
|
||||
channel-type.wundergroundupdatereceiver.ozone.description = Ozone, ppb.
|
||||
channel-type.wundergroundupdatereceiver.pm10-mass.label = PM10 Mass
|
||||
channel-type.wundergroundupdatereceiver.pm10-mass.description = PM10 mass, µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.pm2_5-mass.label = PM2.5 Mass
|
||||
channel-type.wundergroundupdatereceiver.pm2_5-mass.description = PM2.5 mass, µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.rain-daily.label = Daily Rain
|
||||
channel-type.wundergroundupdatereceiver.rain-daily.description = Rain since the start of the day.
|
||||
channel-type.wundergroundupdatereceiver.rain-monthly.label = Monthly Rain
|
||||
channel-type.wundergroundupdatereceiver.rain-monthly.description = Rain since the start if this month.
|
||||
channel-type.wundergroundupdatereceiver.rain-weekly.label = Weekly Rain
|
||||
channel-type.wundergroundupdatereceiver.rain-weekly.description = Rain since the start of this week.
|
||||
channel-type.wundergroundupdatereceiver.rain-yearly.label = Yearly Rain
|
||||
channel-type.wundergroundupdatereceiver.rain-yearly.description = Rain since the start of this year.
|
||||
channel-type.wundergroundupdatereceiver.rain.label = Hourly Rain
|
||||
channel-type.wundergroundupdatereceiver.rain.description = Rain over the past hour.
|
||||
channel-type.wundergroundupdatereceiver.realtime-frequency.label = Realtime Frequency
|
||||
channel-type.wundergroundupdatereceiver.realtime-frequency.description = How often does the weather station submit measurements
|
||||
channel-type.wundergroundupdatereceiver.so4-ion.label = SO4 ion
|
||||
channel-type.wundergroundupdatereceiver.so4-ion.description = SO4 ion (sulfate, not adjusted for ammonium ion) µG/m3.
|
||||
channel-type.wundergroundupdatereceiver.softwaretype.label = Software Type
|
||||
channel-type.wundergroundupdatereceiver.softwaretype.description = A software type string from the weather station
|
||||
channel-type.wundergroundupdatereceiver.soil-moisture.label = Soil Moisture
|
||||
channel-type.wundergroundupdatereceiver.soil-moisture.description = Soil moisture in %.
|
||||
channel-type.wundergroundupdatereceiver.soil-temperature.label = Soil Temperature
|
||||
channel-type.wundergroundupdatereceiver.soil-temperature.description = Soil temperature.
|
||||
channel-type.wundergroundupdatereceiver.solarradiation.label = Solar Radiation
|
||||
channel-type.wundergroundupdatereceiver.solarradiation.description = Solar radiation
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide-trace-levels.label = Sulfur Dioxide Trace Levels
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide-trace-levels.description = Sulfur Dioxide, trace levels ppb.
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide.label = Sulfur Dioxide
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide.description = Sulfur Dioxide, conventional ppb.
|
||||
channel-type.wundergroundupdatereceiver.total-reactive-nitrogen.label = Total Reactive Nitrogen
|
||||
channel-type.wundergroundupdatereceiver.total-reactive-nitrogen.description = Total reactive nitrogen.
|
||||
channel-type.wundergroundupdatereceiver.uv.label = UV Index
|
||||
channel-type.wundergroundupdatereceiver.uv.description = UV index.
|
||||
channel-type.wundergroundupdatereceiver.visibility.label = Visibility
|
||||
channel-type.wundergroundupdatereceiver.visibility.description = Visibility.
|
||||
channel-type.wundergroundupdatereceiver.wind-chill.label = Wind Chill
|
||||
channel-type.wundergroundupdatereceiver.wind-chill.description = The apparent wind chill temperature.
|
||||
channel-type.wundergroundupdatereceiver.wind-direction-avg-2min.label = Wind Direction 2min Average
|
||||
channel-type.wundergroundupdatereceiver.wind-direction-avg-2min.description = 2 minute average wind direction.
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-direction-10min.label = Gust Direction 10min Average
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-direction-10min.description = 10 minute average gust direction.
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-direction.label = Gust Direction
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-direction.description = Current wind gust direction expressed as an angle using software specific time period.
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed-10min.label = Gust Speed 10min Average
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed-10min.description = 10 minute average gust speed.
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed.label = Current Gust Speed
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed.description = Current wind gust speed, using software specific time period.
|
||||
channel-type.wundergroundupdatereceiver.wind-speed-avg-2min.label = Wind Speed 2min Average
|
||||
channel-type.wundergroundupdatereceiver.wind-speed-avg-2min.description = 2 minute average wind speed.
|
||||
channel-type.wundergroundupdatereceiver.wind-speed.label = Current Wind Speed
|
||||
channel-type.wundergroundupdatereceiver.wind-speed.description = Current wind speed, using software specific time period.
|
||||
@@ -0,0 +1,129 @@
|
||||
binding.wundergroundupdatereceiver.name=Wundergroundopdateringsmodtager Binding
|
||||
binding.wundergroundupdatereceiver.description=Denne binding gør det muligt at modtage opdateringer fra vejrstationer som sender målinger til https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php.
|
||||
|
||||
thing-type.wundergroundupdatereceiver.description=En endpoint til modtagelse og videreformidling af opdateringer fra vejrstationer, som kan opdatere wunderground.com
|
||||
thing-type.wundergroundupdatereceiver.config.label=Stationsid som er konfigureret i vejstationen.
|
||||
thing-type.wundergroundupdatereceiver.config.description=<![CDATA[<br /> \
|
||||
wunderground.com api'en kræver en stationsid, som stammer fra WeatherUnderground \
|
||||
kontoen man sender målinger til.<br /> \
|
||||
<br /> \
|
||||
Her bliver den brugt til at skelne mellem ting instanser, så flere vejrstationers opdateringer kan håndteres \
|
||||
eller flere slags måleenheders målinger kan aggregeres. \
|
||||
Hvis man ikke agter at videresende målinger til wunderground.com, kan man sætte dette til en ikke-tom streng.
|
||||
|
||||
channel-group-type.wundergroundupdatereceiver.metadata-group.description=Metadata fra den sidste opdatering
|
||||
channel-group-type.wundergroundupdatereceiver.wind-group.description=Vindmålinger
|
||||
channel-group-type.wundergroundupdatereceiver.wind-group.label=Vind
|
||||
channel-group-type.wundergroundupdatereceiver.temperature-group.description=Temperaturmålinger
|
||||
channel-group-type.wundergroundupdatereceiver.temperature-group.label=Temperatur
|
||||
channel-group-type.wundergroundupdatereceiver.humidity-group.description=Fugtighedsmålinger
|
||||
channel-group-type.wundergroundupdatereceiver.humidity-group.label=Fugtighed
|
||||
channel-group-type.wundergroundupdatereceiver.rain-group.description=Regnmålinger
|
||||
channel-group-type.wundergroundupdatereceiver.rain-group.label=Regn
|
||||
channel-group-type.wundergroundupdatereceiver.sunlight-group.description=Lysmålinger
|
||||
channel-group-type.wundergroundupdatereceiver.sunlight-group.label=Sollys
|
||||
channel-group-type.wundergroundupdatereceiver.pressure-group.description=Barometertrykmålinger
|
||||
channel-group-type.wundergroundupdatereceiver.pressure-group.label=Barometertryk
|
||||
channel-group-type.wundergroundupdatereceiver.pollution-group.description=Målinger af atmosfærisk forurening
|
||||
channel-group-type.wundergroundupdatereceiver.pollution-group.label=Forurening
|
||||
|
||||
channel-type.wundergroundupdatereceiver.last-received-datetime.description=Tidspunkt for sidst modtaget opdatering fra stationen
|
||||
channel-type.wundergroundupdatereceiver.last-received-datetime.label=Sidst modtaget
|
||||
channel-type.wundergroundupdatereceiver.dateutc.description=Stationens værdi for sidst opdateringstidspunkt. Kan være 'now'
|
||||
channel-type.wundergroundupdatereceiver.dateutc.label=Sidst opdateret
|
||||
channel-type.system.low-battery.description=Stationens batteri er ved være flad
|
||||
channel-type.system.low-battery.label=Lav batteri
|
||||
channel-type.wundergroundupdatereceiver.realtime-frequency.description=Stationens angivelse af opdateringsfrekvensen
|
||||
channel-type.wundergroundupdatereceiver.realtime-frequency.label=Opdateringsfrekvens
|
||||
channel-type.wundergroundupdatereceiver.wind-speed.description=Øjeblikkelig vindhastighed i mph
|
||||
channel-type.wundergroundupdatereceiver.wind-speed.label=Vindhastighed
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed.description=Øjeblikkelig vindstødshastighed
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed.label=Vindstødshastighed
|
||||
channel-type.system.wind-direction.description=Øjeblikkelig vindretning som vinkel
|
||||
channel-type.system.wind-direction.label=Vindretning
|
||||
channel-type.wundergroundupdatereceiver.wind-speed-avg-2min.description=Gennemsnitlig vindhastighed i de sidste 2 minutter
|
||||
channel-type.wundergroundupdatereceiver.wind-speed-avg-2min.label=Gns. vindhastighed (2min)
|
||||
channel-type.wundergroundupdatereceiver.wind-direction-avg-2min.description=Gennemsnitlig vindretning i de sidste 2 minutter som vinkel
|
||||
channel-type.wundergroundupdatereceiver.wind-direction-avg-2min.label=Gns. vindretning (2min)
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed-10min.description=Gennemsnitlig vindstæshastighed i de sidste 10 minutter
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-speed-10min.label=Gns. vindstødshastighed (10min)
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-direction-10min.description=Gennemsnitlig vindstødsretning i de sidste 10 minutter som vinkel
|
||||
channel-type.wundergroundupdatereceiver.wind-gust-direction-10min.label=Gns. vindstødsretning (10min)
|
||||
channel-type.wundergroundupdatereceiver.humidity.description=Udendørs fugtighed i pct
|
||||
channel-type.wundergroundupdatereceiver.humidity.label=Udendørs fugtighed
|
||||
channel-type.wundergroundupdatereceiver.indoor-humidity.description=Indendørs fugtighed i pct
|
||||
channel-type.wundergroundupdatereceiver.indoor-humidity.label=Indendørs fugtighed
|
||||
channel-type.wundergroundupdatereceiver.dew-point.description=Dugpunkt
|
||||
channel-type.wundergroundupdatereceiver.dew-point.label=Dugpunkt
|
||||
channel-type.wundergroundupdatereceiver.wind-chill.description=Kuldeindeks
|
||||
channel-type.wundergroundupdatereceiver.wind-chill.label=Kuldeindeks
|
||||
channel-type.system.temperature.description=Udendørs temperatur
|
||||
channel-type.system.temperature.label=Udendørs temperatur
|
||||
channel-type.wundergroundupdatereceiver.indoor-temperature.description=Indendørs temperatur
|
||||
channel-type.wundergroundupdatereceiver.indoor-temperature.label=Indendørs temperatur
|
||||
channel-type.wundergroundupdatereceiver.soil-temperature.description=Jordtemeperatur
|
||||
channel-type.wundergroundupdatereceiver.soil-temperature.label=Jordtemeperatur
|
||||
channel-type.wundergroundupdatereceiver.rain.description=Regnmængde i den sidste time
|
||||
channel-type.wundergroundupdatereceiver.rain.label=Regn (sidste time)
|
||||
channel-type.wundergroundupdatereceiver.rain-daily.description=Regnmængde siden starten af dagen
|
||||
channel-type.wundergroundupdatereceiver.rain-daily.label=Regn (i dag)
|
||||
channel-type.wundergroundupdatereceiver.rain-weekly.description=Regnmængde siden starten af ugen
|
||||
channel-type.wundergroundupdatereceiver.rain-weekly.label=Regn (denne uge)
|
||||
channel-type.wundergroundupdatereceiver.rain-monthly.description=Regnmængde siden starten af måneden
|
||||
channel-type.wundergroundupdatereceiver.rain-monthly.label=Regn (denne måned)
|
||||
channel-type.wundergroundupdatereceiver.rain-yearly.description=Regnmængde siden starten af året
|
||||
channel-type.wundergroundupdatereceiver.rain-yearly.label=Regn (i år)
|
||||
channel-type.wundergroundupdatereceiver.metar.description=Vejrmelding i METAR format
|
||||
channel-type.wundergroundupdatereceiver.metar.label=METAR vejrmelding
|
||||
channel-type.wundergroundupdatereceiver.clouds.description=Skydække
|
||||
channel-type.wundergroundupdatereceiver.clouds.label=Skydække i METAR format
|
||||
channel-type.wundergroundupdatereceiver.soil-moisture.description=Jordfugtighed i pct
|
||||
channel-type.wundergroundupdatereceiver.soil-moisture.label=Jordfugtighed
|
||||
channel-type.wundergroundupdatereceiver.leafwetness.description=Bladfugtighed i pct
|
||||
channel-type.wundergroundupdatereceiver.leafwetness.label=Bladfugtighed
|
||||
channel-type.wundergroundupdatereceiver.solarradiation.description=Solstråling i W/m2
|
||||
channel-type.wundergroundupdatereceiver.solarradiation.label=Solstråling
|
||||
channel-type.wundergroundupdatereceiver.uv.description=UV index
|
||||
channel-type.wundergroundupdatereceiver.uv.label=UV index
|
||||
channel-type.wundergroundupdatereceiver.visibility.description=Sigtbarhed
|
||||
channel-type.wundergroundupdatereceiver.visibility.label=Sigtbarhed
|
||||
channel-type.wundergroundupdatereceiver.nitric-oxide.description=
|
||||
channel-type.wundergroundupdatereceiver.nitric-oxide.label=Nitrogenoxid
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-measured.description=Målt nitrogendioxid i ppb
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-measured.label=Nitrogendioxid
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-nox-no.description=Beregnet nitrogendioxid i ppb
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-nox-no.label=Beregnet nitrogendioxid
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-noy-no.description=Beregnet nitrogendioxid Y
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-dioxide-noy-no.label=Beregnet nitrogendioxid Y
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-oxides.description=Nitrogenoxider
|
||||
channel-type.wundergroundupdatereceiver.nitrogen-oxides.label=Nitrogenoxid i ppb
|
||||
channel-type.wundergroundupdatereceiver.total-reactive-nitrogen.description=Reactive nitrogen ialt
|
||||
channel-type.wundergroundupdatereceiver.total-reactive-nitrogen.label=Reactive nitrogen ialt
|
||||
channel-type.wundergroundupdatereceiver.no3-ion.description=Nitrat tæthed
|
||||
channel-type.wundergroundupdatereceiver.no3-ion.label=Nitrat
|
||||
channel-type.wundergroundupdatereceiver.so4-ion.description=Sulfat tæthed
|
||||
channel-type.wundergroundupdatereceiver.so4-ion.label=Sulfat
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide.description=Svovldioxid i ppb
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide.label=Svovldioxid
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide-trace-levels.description=Svovldioxid sporelementer
|
||||
channel-type.wundergroundupdatereceiver.sulfur-dioxide-trace-levels.label=Svovldioxid sporelementer
|
||||
channel-type.wundergroundupdatereceiver.elemental-carbon.description=Kulstofselementer
|
||||
channel-type.wundergroundupdatereceiver.elemental-carbon.label=Kulstofselementer
|
||||
channel-type.wundergroundupdatereceiver.organic-carbon.description=Organisk kulstof
|
||||
channel-type.wundergroundupdatereceiver.organic-carbon.label=Organisk kulstof
|
||||
channel-type.wundergroundupdatereceiver.black-carbon.description=Sort kulstof
|
||||
channel-type.wundergroundupdatereceiver.black-carbon.label=Sort kulstof
|
||||
channel-type.wundergroundupdatereceiver.aethalometer.description=Aethalometer
|
||||
channel-type.wundergroundupdatereceiver.aethalometer.label=Aethalometer
|
||||
channel-type.wundergroundupdatereceiver.pm2_5-mass.description=PM2.5 massetæthed
|
||||
channel-type.wundergroundupdatereceiver.pm2_5-mass.label=PM2.5 massetæthed
|
||||
channel-type.wundergroundupdatereceiver.pm10-mass.description=PM10 massetæthed
|
||||
channel-type.wundergroundupdatereceiver.pm10-mass.label=PM10 massetæthed
|
||||
channel-type.wundergroundupdatereceiver.ozone.description=Ozon
|
||||
channel-type.wundergroundupdatereceiver.ozone.label=Ozon
|
||||
channel-type.wundergroundupdatereceiver.softwaretype.description=En software type streng fra vejrstationen
|
||||
channel-type.wundergroundupdatereceiver.softwaretype.label=Software type
|
||||
channel-type.wundergroundupdatereceiver.last-query-state.description=Querystring delen af den sidste query
|
||||
channel-type.wundergroundupdatereceiver.last-query-state.label=Den sidste query
|
||||
channel-type.wundergroundupdatereceiver.last-query-trigger.description=Querystring delen af den sidste query
|
||||
channel-type.wundergroundupdatereceiver.last-query-trigger.label=Den sidste query
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" ?>
|
||||
<thing:thing-descriptions bindingId="wundergroundupdatereceiver"
|
||||
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">
|
||||
|
||||
<channel-group-type id="metadata-group">
|
||||
<label>Metadata</label>
|
||||
<description>Metadata regarding the last submission</description>
|
||||
<category>Text</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="wind-group">
|
||||
<label>Wind</label>
|
||||
<description>Wind measurements</description>
|
||||
<category>Wind</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="temperature-group">
|
||||
<label>Temperature</label>
|
||||
<description>Temperature measurements</description>
|
||||
<category>Temperature</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="humidity-group">
|
||||
<label>Moisture</label>
|
||||
<description>Moisture measurements</description>
|
||||
<category>Humidity</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="rain-group">
|
||||
<label>Rain</label>
|
||||
<description>Rain measurements</description>
|
||||
<category>Rain</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="sunlight-group">
|
||||
<label>Sunlight</label>
|
||||
<description>Sunlight measurements</description>
|
||||
<category>Sun_Clouds</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="pressure-group">
|
||||
<label>Pressure</label>
|
||||
<description>Barometric measurements</description>
|
||||
<category>Pressure</category>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="pollution-group">
|
||||
<label>Pollution</label>
|
||||
<description>Pollutant measurements</description>
|
||||
<category>Pollution</category>
|
||||
</channel-group-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,580 @@
|
||||
<?xml version="1.0" ?>
|
||||
<thing:thing-descriptions bindingId="wundergroundupdatereceiver"
|
||||
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">
|
||||
|
||||
<channel-type id="last-received-datetime">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Received</label>
|
||||
<description>The date and time of the last update.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Point</tag>
|
||||
<tag>Timestamp</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dateutc" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Updated</label>
|
||||
<description>The date and time of the last update in UTC as submitted by the weather station. This can be 'now'.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Point</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dateutc-datetime" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Updated as DateTime</label>
|
||||
<description>The date and time of the last update in UTC as submitted by the weather station converted to a DateTime
|
||||
value. In case of 'now', the current time is used.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Point</tag>
|
||||
<tag>Timestamp</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-speed">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Current Wind Speed</label>
|
||||
<description>Current wind speed, using software specific time period.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-gust-speed">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Current Gust Speed</label>
|
||||
<description>Current wind gust speed, using software specific time period.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-gust-direction">
|
||||
<item-type>Number:Angle</item-type>
|
||||
<label>Gust Direction</label>
|
||||
<description>Current wind gust direction expressed as an angle using software specific time period.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-speed-avg-2min" advanced="true">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Wind Speed 2min Average</label>
|
||||
<description>2 minute average wind speed.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-direction-avg-2min" advanced="true">
|
||||
<item-type>Number:Angle</item-type>
|
||||
<label>Wind Direction 2min Average</label>
|
||||
<description>2 minute average wind direction.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-gust-speed-10min" advanced="true">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Gust Speed 10min Average</label>
|
||||
<description>10 minute average gust speed.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-gust-direction-10min" advanced="true">
|
||||
<item-type>Number:Angle</item-type>
|
||||
<label>Gust Direction 10min Average</label>
|
||||
<description>10 minute average gust direction.</description>
|
||||
<category>Wind</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>Humidity in %.</description>
|
||||
<category>Humidity</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Humidity</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="indoor-humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Indoor Humidity</label>
|
||||
<description>Indoor humidity in %.</description>
|
||||
<category>Humidity</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Humidity</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dew-point" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Dew Point</label>
|
||||
<description>Outdoor dew point.</description>
|
||||
<category>Humidity</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-chill" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Wind Chill</label>
|
||||
<description>The apparent wind chill temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Wind</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- for extra outdoor sensors use temp2f, temp3f, and so on -->
|
||||
<channel-type id="indoor-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Indoor Temperature</label>
|
||||
<description>Indoor temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- for sensors 2,3,4 use soiltemp2f, soiltemp3f, and soiltemp4f -->
|
||||
<channel-type id="soil-temperature" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Soil Temperature</label>
|
||||
<description>Soil temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Hourly Rain</label>
|
||||
<description>Rain over the past hour.</description>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain-daily">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Daily Rain</label>
|
||||
<description>Rain since the start of the day.</description>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain-weekly" advanced="true">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Weekly Rain</label>
|
||||
<description>Rain since the start of this week.</description>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain-monthly" advanced="true">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Monthly Rain</label>
|
||||
<description>Rain since the start if this month.</description>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain-yearly" advanced="true">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Yearly Rain</label>
|
||||
<description>Rain since the start of this year.</description>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="metar" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>METAR Weather Report</label>
|
||||
<description>METAR formatted weather report</description>
|
||||
<category>Sun_Clouds</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="clouds" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Cloud Cover</label>
|
||||
<description>METAR style cloud cover.</description>
|
||||
<category>Sun_Clouds</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- for sensors 2,3,4 use soilmoisture2, soilmoisture3, and soilmoisture4 -->
|
||||
<channel-type id="soil-moisture" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Soil Moisture</label>
|
||||
<description>Soil moisture in %.</description>
|
||||
<category>Moisture</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Water</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f %%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- for sensor 2 use leafwetness2 -->
|
||||
<channel-type id="leafwetness" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Leaf Wetness</label>
|
||||
<description>Leaf wetness in %.</description>
|
||||
<category>Moisture</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Water</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="solarradiation">
|
||||
<item-type>Number:Intensity</item-type>
|
||||
<label>Solar Radiation</label>
|
||||
<description>Solar radiation</description>
|
||||
<category>Sun</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Light</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uv">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>UV Index</label>
|
||||
<description>UV index.</description>
|
||||
<category>Sun</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Ultraviolet</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="visibility" advanced="true">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Visibility</label>
|
||||
<description>Visibility.</description>
|
||||
<category>Sun_Clouds</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Pollution Fields: -->
|
||||
<channel-type id="nitric-oxide" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Nitric Oxide</label>
|
||||
<description>Nitric Oxide ppm.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="nitrogen-dioxide-measured" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Nitrogen Dioxide</label>
|
||||
<description>Nitrogen Dioxide, true measure ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="nitrogen-dioxide-nox-no" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>NO2 X computed</label>
|
||||
<description>NO2 computed, NOx-NO ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="nitrogen-dioxide-noy-no" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>NO2 Y computed, NOy-NO ppb</label>
|
||||
<description>NO2 computed, NOy-NO ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="nitrogen-oxides" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Nitrogen Oxides</label>
|
||||
<description>Nitrogen Oxides ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="total-reactive-nitrogen" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Total Reactive Nitrogen</label>
|
||||
<description>Total reactive nitrogen.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="no3-ion" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>NO3 ion</label>
|
||||
<description>NO3 ion (nitrate, not adjusted for ammonium ion) µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="so4-ion" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>SO4 ion</label>
|
||||
<description>SO4 ion (sulfate, not adjusted for ammonium ion) µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sulfur-dioxide" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Sulfur Dioxide</label>
|
||||
<description>Sulfur Dioxide, conventional ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sulfur-dioxide-trace-levels" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Sulfur Dioxide Trace Levels</label>
|
||||
<description>Sulfur Dioxide, trace levels ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="carbon-monoxide" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Carbon Monoxide</label>
|
||||
<description>Carbon Monoxide, conventional ppm.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="carbon-monoxide-trace-levels" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Carbon Monoxide Trace Levels</label>
|
||||
<description>Carbon Monoxide, trace levels ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="elemental-carbon" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Elemental Carbon</label>
|
||||
<description>Elemental Carbon, PM2.5 µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="organic-carbon" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Organic Carbon</label>
|
||||
<description>Organic Carbon, not adjusted for oxygen and hydrogen, PM2.5 µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="black-carbon" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Black Carbon</label>
|
||||
<description>Black Carbon at 880 nm, µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="aethalometer" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Second Channel of Aethalometer</label>
|
||||
<description>second channel of Aethalometer at 370 nm, µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm2_5-mass" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM2.5 Mass</label>
|
||||
<description>PM2.5 mass, µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm10-mass" advanced="true">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM10 Mass</label>
|
||||
<description>PM10 mass, µG/m3.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ozone" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Ozone</label>
|
||||
<description>Ozone, ppb.</description>
|
||||
<category>Pollution</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="softwaretype" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Software Type</label>
|
||||
<description>A software type string from the weather station</description>
|
||||
<category>Text</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="realtime-frequency" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Realtime Frequency</label>
|
||||
<description>How often does the weather station submit measurements</description>
|
||||
<category>Number</category>
|
||||
<state readOnly="true" pattern="%.0f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="last-query-state" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<kind>state</kind>
|
||||
<label>The last query</label>
|
||||
<description>The part of the last query after the first unurlencoded '?'</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="last-query-trigger">
|
||||
<item-type>String</item-type>
|
||||
<kind>trigger</kind>
|
||||
<label>The last query</label>
|
||||
<description>The part of the last query after the first unurlencoded '?'</description>
|
||||
<event/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="wundergroundupdatereceiver"
|
||||
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="wundergroundUpdateReceiver">
|
||||
<label>Update Receiver</label>
|
||||
<description>An endpoint thing that can receive and propagate HTTP GET updates meant for a particular station id at
|
||||
wunderground.com</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="metadata" typeId="metadata-group"/>
|
||||
<channel-group id="wind" typeId="wind-group"/>
|
||||
<channel-group id="temperature" typeId="temperature-group"/>
|
||||
<channel-group id="humidity" typeId="humidity-group"/>
|
||||
<channel-group id="rain" typeId="rain-group"/>
|
||||
<channel-group id="sunlight" typeId="sunlight-group"/>
|
||||
<channel-group id="pressure" typeId="pressure-group"/>
|
||||
<channel-group id="pollution" typeId="pollution-group"/>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>stationId</representation-property>
|
||||
<config-description>
|
||||
<parameter name="stationId" type="text" required="true" pattern="\w+">
|
||||
<label>Station ID</label>
|
||||
<description><![CDATA[<br />
|
||||
The wunderground.com update api requires a station id, that is defined for the WeatherUnderground
|
||||
account measurements are to be submitted to.<br />
|
||||
<br />
|
||||
In this binding it is used to identify a unique thing, so each weather-station or
|
||||
other apparatus submitting measurements can have a separate id, but if you don't intend to forward
|
||||
the observations to wunderground.com, this value can be any non-blank string.
|
||||
]]>
|
||||
</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user