added migrated 2.x add-ons

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

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.nzwateralerts</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@@ -0,0 +1,73 @@
# NZ Water Alerts Binding
Get Water Alert Levels for cities in New Zealand.
Getting this alert level can help you script and automate smarter tasks for water and avoid getting penalized from your distract or local council.
> Example: Disable automated spinklers based on a level 3 or 4 water alert level
This Binding scrapes multiple websites for Water Levels:
* Northland's [BeWaterWise Website](https://bewaterwise.org.nz/)
* Waikato's [Smart Water Website](https://www.smartwater.org.nz/)
* Napier's [Council Website](https://www.napier.govt.nz)
## Thing Configuration
The binding and thing ID is `nzwateralerts:wateralert`.
### Configuration Values
| Value | Type | Description |
| --------------- | ------------ | -------------------------------------- |
| location | string | The location to get water data from. Refer to the list below for values. |
| refreshInterval | number | The time interval (in hours) to refresh the data.
### Supported city/area list
| City | Config Value |
| ------------------------ | ------------------------------------------ |
| Bream Bay | bewaterwise:whangarei:breambay |
| Dargaville & Baylys | bewaterwise:kaipara:dargavilleampbaylys |
| Glinks Gully | bewaterwise:kaipara:glinksgully |
| Hamilton City | smartwater:hamilton:hamilton |
| Kaikohe / Ngawha | bewaterwise:farnorth:kaikohengawha |
| Kaitaia | bewaterwise:farnorth:kaitaia |
| Kerikeri / Waipapa | bewaterwise:farnorth:kerikeriwaipapa |
| Mangapai | bewaterwise:whangarei:mangapai |
| Mangawhai | bewaterwise:kaipara:mangawhai |
| Maungakaramea | bewaterwise:whangarei:maungakaramea |
| Maungaturoto | bewaterwise:kaipara:maungaturoto |
| Moerewa / Kawakawa | bewaterwise:farnorth:moerewakawakawa |
| Napier | napiercitycouncil:napier:napier |
| Okaihau | bewaterwise:farnorth:okaihau |
| Opononi / Omapere | bewaterwise:farnorth:opononiomapere |
| Rawene | bewaterwise:farnorth:rawene |
| Ruawai | bewaterwise:kaipara:ruawai |
| Russell | bewaterwise:farnorth:russell |
| Waipa District | smartwater:waipa:waipa |
| Waikato District | smartwater:waikato:waikato |
| Waitangi / Paihia / Opua | bewaterwise:farnorth:waitangipaihiaopua |
| Whangarei | bewaterwise:whangarei:whangarei |
### Example
```
Thing nzwateralerts:wateralert "HCC" [ location="smartwater:hamilton:hamilton", refreshInterval="4" ]
```
The above gets the Water Alert level for Hamilton and refreshes this data every 4 hours.
## Channels
There is only one channel with this binding labelled `alertlevel` which contains a Number 0-4 to represent the alert level.
Depending on your region, either Alert Level 0 or 1 can represent _No Water Restrictions_.
Check with your regional council for further details.
## Other Cities
At present the supported cities were implemented by scraping the web page on the respective website which contains the restriction information.
**No councils have this data in a programmatic format easily accessible to software.**
Most won't have pages which contain the current alert level and only offer alerts via twitter or text.
If you can convince your council to always have a page displaying the current alert level (even if none is in effect) then I can attempt to parse the page for inclusion in this Binding.

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.nzwateralerts</artifactId>
<name>openHAB Add-ons :: Bundles :: NZ Water Alerts Binding</name>
</project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding. nzwateralerts-${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-nzwateralerts" description="NZ Water Alerts Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.nzwateralerts/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.nzwateralerts.internal.api.BeWaterWise;
import org.openhab.binding.nzwateralerts.internal.api.NapierCityCouncil;
import org.openhab.binding.nzwateralerts.internal.api.SmartWater;
import org.openhab.binding.nzwateralerts.internal.api.WaterWebService;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link NZWaterAlertsBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class NZWaterAlertsBindingConstants {
private static final String BINDING_ID = "nzwateralerts";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_WATERALERT = new ThingTypeUID(BINDING_ID, "wateralert");
// List of all Channel ids
public static final String CHANNEL_ALERTLEVEL = "alertlevel";
// List of all supported services
public static final List<WaterWebService> WATER_WEB_SERVICES = Arrays
.asList(new WaterWebService[] { new SmartWater(), new BeWaterWise(), new NapierCityCouncil() });
}

View File

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

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.api;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BeWaterWise} class contains the logic to get data the
* bewaterwise.org.nz website.
*
* Northland Regional Council
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class BeWaterWise implements WaterWebService {
private final Logger logger = LoggerFactory.getLogger(BeWaterWise.class);
private static final String HOSTNAME = "https://bewaterwise.org.nz";
private static final String REGION_FARNORTH = "/current-water-levels_far-north/";
private static final String REGION_WHANGAREI = "/current-water-levels_whangarei/";
private static final String REGION_KAIPARA = "/current-water-levels_kaipara/";
private static final String PATTERN = "vc_text_separator.*?<span>(.*?)<\\/span>.*?water-level-([0-4]).*?";
private static final Pattern REGEX = Pattern.compile(PATTERN,
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
@Override
public String service() {
return "bewaterwise";
}
@Override
public String endpoint(final String region) {
switch (region.toLowerCase()) {
case "farnorth":
return HOSTNAME + REGION_FARNORTH;
case "whangarei":
return HOSTNAME + REGION_WHANGAREI;
case "kaipara":
return HOSTNAME + REGION_KAIPARA;
}
return "";
}
@Override
public int findWaterLevel(final String data, final String area) {
final Matcher matches = REGEX.matcher(data);
while (matches.find()) {
final String dataArea = matches.group(1).replaceAll("\\W", "");
final String level = matches.group(2);
logger.debug("Data Area {} Level {}", dataArea, level);
if (dataArea.equalsIgnoreCase(area)) {
return Integer.valueOf(level);
}
}
return -1;
}
}

View File

@@ -0,0 +1,84 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.api;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link NapierCityCouncil} class contains the logic to get data the
* www.napier.govt.nz website.
*
* Napier City Council
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class NapierCityCouncil implements WaterWebService {
private final Logger logger = LoggerFactory.getLogger(NapierCityCouncil.class);
private static final String HOSTNAME = "https://www.napier.govt.nz";
private static final String REGION_NAPIER = "/services/water/water-restrictions/";
private static final String PATTERN = "\"waterstat\".*?<p>.*?at (.*?) Restrictions.*?</div>";
private static final Pattern REGEX = Pattern.compile(PATTERN,
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
@Override
public String service() {
return "napiercitycouncil";
}
@Override
public String endpoint(final String region) {
switch (region.toLowerCase()) {
case "napier":
return HOSTNAME + REGION_NAPIER;
}
return "";
}
@Override
public int findWaterLevel(final String data, final String area) {
final Matcher matches = REGEX.matcher(data);
while (matches.find()) {
final String level = matches.group(1);
logger.debug("Data Level {}", level);
switch (level.toLowerCase()) {
case "no":
return 0;
case "level one":
return 1;
case "level two":
return 2;
case "level three":
return 3;
case "level four":
return 4;
}
}
return -1;
}
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.api;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SmartWater} class contains the logic to get data the
* SmartWater.org.nz website.
*
* Waikato Regional Council
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class SmartWater implements WaterWebService {
private final Logger logger = LoggerFactory.getLogger(SmartWater.class);
private static final String HOSTNAME = "http://www.smartwater.org.nz";
private static final String REGION_HAMILTON = "/alert-levels/hamilton-city";
private static final String REGION_WAIKATO = "/alert-levels/waikato-district-council";
private static final String REGION_WAIPA = "/alert-levels/waipa-district-council";
private static final String PATTERN = "/assets/Alert-Level-Images/water-alert-([1-4]|no)-large.svg.*?";
private static final Pattern REGEX = Pattern.compile(PATTERN,
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
@Override
public String service() {
return "smartwater";
}
@Override
public String endpoint(final String region) {
switch (region.toLowerCase()) {
case "hamilton":
return HOSTNAME + REGION_HAMILTON;
case "waikato":
return HOSTNAME + REGION_WAIKATO;
case "waipa":
return HOSTNAME + REGION_WAIPA;
}
return "";
}
@Override
public int findWaterLevel(final String data, final String area) {
final Matcher matches = REGEX.matcher(data);
while (matches.find()) {
String level = matches.group(1);
logger.debug("Data Level {}", level);
if (level.equalsIgnoreCase("no")) {
logger.debug("Convert Data Level to 0");
level = "0";
}
return Integer.valueOf(level);
}
return -1;
}
}

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.api;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link TaupoDistrictCouncil} class contains the logic to get data the
* www.taupodc.govt.nz website.
*
* Taupo District Council
*
* NOTE: This is currently a placeholder. This region needs to go into restrictions
* first so I can parse the correct output. -Stewart Cossey
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class TaupoDistrictCouncil implements WaterWebService {
private final Logger logger = LoggerFactory.getLogger(TaupoDistrictCouncil.class);
private static final String HOSTNAME = "https://www.taupodc.govt.nz";
private static final String REGION_TAUPO = "/transport-and-water/water-conservation";
private static final String PATTERN = "div class=\"rc\".*?<tbody>.*?<strong>.*?<strong>(.*?) restrictions</strong>";
private static final Pattern REGEX = Pattern.compile(PATTERN,
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
@Override
public String service() {
return "taupodistrictcouncil";
}
@Override
public String endpoint(final String region) {
switch (region.toLowerCase()) {
case "taupo":
return HOSTNAME + REGION_TAUPO;
}
return "";
}
@Override
public int findWaterLevel(final String data, final String area) {
final Matcher matches = REGEX.matcher(data);
while (matches.find()) {
final String level = matches.group(1);
logger.debug("Data Level {}", level);
switch (level.toLowerCase()) {
case "no":
return 0;
case "level one":
case "level 1":
return 1;
case "level two":
case "level 2":
return 2;
case "level three":
case "level 3":
return 3;
case "level four":
case "level 4":
return 4;
}
}
return -1;
}
}

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.api;
import static org.openhab.binding.nzwateralerts.internal.NZWaterAlertsBindingConstants.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link WebClient} class contains the logic to get data from a URL.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class WaterAlertWebClient {
private final Logger logger = LoggerFactory.getLogger(WaterAlertWebClient.class);
private static final int REQUEST_TIMEOUT = 10;
private final HttpClient httpClient;
private final String webService;
private final String region;
private final String area;
private @Nullable WaterWebService service = null;
public WaterAlertWebClient(final HttpClient httpClient, final String location) {
this.httpClient = httpClient;
final String[] locationSegmented = location.split(":", 3);
webService = locationSegmented[0];
region = locationSegmented[1];
area = locationSegmented[2];
for (final WaterWebService srv : WATER_WEB_SERVICES) {
logger.trace("Checking service {}", srv.service());
if (locationSegmented[0].equalsIgnoreCase(srv.service())) {
logger.trace("Found service {}", srv.service());
service = srv;
}
}
if (service == null) {
logger.debug("Service could not be found for {}", locationSegmented[0]);
}
}
public @Nullable Integer getLevel() {
ContentResponse response;
final WaterWebService localService = service;
try {
if (localService != null) {
logger.debug("Getting Water Level from service {} region {} area {}", webService, region, area);
final String endpoint = localService.endpoint(region);
logger.trace("Getting data from endpoint {} with timeout {}", endpoint, REQUEST_TIMEOUT);
response = httpClient.newRequest(endpoint).timeout(REQUEST_TIMEOUT, TimeUnit.SECONDS).send();
final int waterLevel = localService.findWaterLevel(response.getContentAsString(), area);
logger.debug("Got water level {}", waterLevel);
return waterLevel;
} else {
logger.debug("Service, region is null");
return null;
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Error when attempting to get Water Level {}", e.getMessage());
return null;
}
}
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.api;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link WebService} class contains the common interfaces for the different
* services.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public interface WaterWebService {
String service();
String endpoint(String region);
int findWaterLevel(String data, String area);
}

View File

@@ -0,0 +1,130 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.binder;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.nzwateralerts.internal.NZWaterAlertsConfiguration;
import org.openhab.binding.nzwateralerts.internal.api.WaterAlertWebClient;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link NZWaterAlertsController} is responsible for handling the connection
* between the handler and API.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class NZWaterAlertsBinder {
private @Nullable WaterAlertWebClient webClient;
private final Logger logger = LoggerFactory.getLogger(NZWaterAlertsBinder.class);
private final Set<NZWaterAlertsBinderListener> listeners = new CopyOnWriteArraySet<>();
private @Nullable ScheduledFuture<?> future;
private final ScheduledExecutorService scheduler;
private int refreshInterval = 5;
public NZWaterAlertsBinder(final HttpClient httpClient, @Nullable final NZWaterAlertsConfiguration config,
final ScheduledExecutorService scheduler) {
this.scheduler = scheduler;
if (config != null) {
final String localLocation = config.location;
if (localLocation == null) {
for (final NZWaterAlertsBinderListener listener : listeners) {
listener.updateBindingStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Location is not set.");
}
} else {
this.webClient = new WaterAlertWebClient(httpClient, localLocation);
refreshInterval = config.refreshInterval;
}
} else {
for (final NZWaterAlertsBinderListener listener : listeners) {
listener.updateBindingStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not create webClient, a parameter is null");
}
logger.debug("Create Binder failed due to null config item");
}
}
public void update() {
final WaterAlertWebClient localWebClient = webClient;
if (localWebClient != null) {
final Integer waterLevel = localWebClient.getLevel();
for (final NZWaterAlertsBinderListener listener : listeners) {
if (waterLevel == null) {
listener.updateBindingStatus(ThingStatus.OFFLINE);
} else {
listener.updateBindingStatus(ThingStatus.ONLINE);
listener.updateWaterLevel(waterLevel);
}
}
}
}
/**
* Registers the given {@link NZWaterAlertsBinderListener}. If it is already
* registered, this method returns immediately.
*
* @param alertsBinderInterface The {@link NZWaterAlertsBinderListener} to be
* registered.
*/
public void registerListener(final NZWaterAlertsBinderListener alertsBinderInterface) {
final boolean isAdded = listeners.add(alertsBinderInterface);
if (isAdded) {
updatePollingState();
}
}
/**
* Unregisters the given {@link NZWaterAlertsBinderListener}. If it is already
* unregistered, this method returns immediately.
*
* @param alertsBinderInterface The {@link NZWaterAlertsBinderListener} to be
* unregistered.
*/
public void unregisterListener(final NZWaterAlertsBinderListener alertsBinderInterface) {
final boolean isRemoved = listeners.remove(alertsBinderInterface);
if (isRemoved) {
updatePollingState();
}
}
private void updatePollingState() {
final ScheduledFuture<?> localFuture = future;
if (localFuture != null && listeners.isEmpty()) {
localFuture.cancel(true);
future = null;
return;
}
if (localFuture == null && !listeners.isEmpty()) {
future = scheduler.scheduleWithFixedDelay(this::update, 0, refreshInterval, TimeUnit.HOURS);
}
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.binder;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
/**
* The {@link NZWaterAlertsControllerListener} is responsible for handling the events from the WebClient and Handler.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public interface NZWaterAlertsBinderListener {
void updateWaterLevel(int level);
void updateBindingStatus(ThingStatus thingStatus);
void updateBindingStatus(ThingStatus thingStatus, ThingStatusDetail thingStatusDetail, String description);
}

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.handler;
import static org.openhab.binding.nzwateralerts.internal.NZWaterAlertsBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.nzwateralerts.internal.NZWaterAlertsConfiguration;
import org.openhab.binding.nzwateralerts.internal.binder.NZWaterAlertsBinder;
import org.openhab.binding.nzwateralerts.internal.binder.NZWaterAlertsBinderListener;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.UnDefType;
/**
* The {@link NZWaterAlertsHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
public class NZWaterAlertsHandler extends BaseThingHandler implements NZWaterAlertsBinderListener {
private @Nullable NZWaterAlertsConfiguration config = null;
private HttpClient httpClient;
private @Nullable NZWaterAlertsBinder binder = null;
public NZWaterAlertsHandler(Thing thing, HttpClient httpClient) {
super(thing);
this.httpClient = httpClient;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
final NZWaterAlertsBinder localBinder = binder;
if (CHANNEL_ALERTLEVEL.equals(channelUID.getId())) {
if (command instanceof RefreshType) {
if (localBinder != null)
localBinder.update();
}
}
}
@Override
public void initialize() {
config = getConfigAs(NZWaterAlertsConfiguration.class);
NZWaterAlertsBinder localBinder = binder = new NZWaterAlertsBinder(httpClient, config, scheduler);
updateStatus(ThingStatus.UNKNOWN);
localBinder.registerListener(this);
}
@Override
public void dispose() {
NZWaterAlertsBinder localBinder = binder;
if (localBinder != null) {
localBinder.unregisterListener(this);
}
super.dispose();
}
@Override
public void handleRemoval() {
NZWaterAlertsBinder localBinder = binder;
if (localBinder != null) {
localBinder.unregisterListener(this);
}
super.handleRemoval();
}
@Override
public void updateWaterLevel(int level) {
if (level == -1) {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ALERTLEVEL), UnDefType.UNDEF);
} else {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ALERTLEVEL), new DecimalType(level));
}
}
@Override
public void updateBindingStatus(ThingStatus thingStatus) {
updateStatus(thingStatus);
}
@Override
public void updateBindingStatus(ThingStatus thingStatus, ThingStatusDetail thingStatusDetail, String description) {
updateStatus(thingStatus, thingStatusDetail, description);
}
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nzwateralerts.internal.handler;
import static org.openhab.binding.nzwateralerts.internal.NZWaterAlertsBindingConstants.*;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link NZWaterAlertsHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Stewart Cossey - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.nzwateralerts", service = ThingHandlerFactory.class)
public class NZWaterAlertsHandlerFactory extends BaseThingHandlerFactory {
private final HttpClient httpClient;
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_WATERALERT);
@Activate
public NZWaterAlertsHandlerFactory(final @Reference HttpClientFactory httpClientFactory) {
this.httpClient = httpClientFactory.getCommonHttpClient();
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_WATERALERT.equals(thingTypeUID)) {
return new NZWaterAlertsHandler(thing, httpClient);
}
return null;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="nzwateralerts" 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>NZ Water Alerts Binding</name>
<description>Water Alert Levels for New Zealand water supply.</description>
<author>Stewart Cossey</author>
</binding:binding>

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nzwateralerts"
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="wateralert">
<label>Alert</label>
<description>Water Alert Levels for New Zealand water supply.</description>
<channels>
<channel id="alertlevel" typeId="alertlevel"/>
</channels>
<config-description>
<parameter name="location" type="text" required="true">
<label>Location</label>
<description>The location to get the Water Alert level for.</description>
<limitToOptions>true</limitToOptions>
<options>
<option value="bewaterwise:whangarei:breambay">Bream Bay</option>
<option value="bewaterwise:kaipara:dargavilleampbaylys">Dargaville &amp; Baylys</option>
<option value="bewaterwise:kaipara:glinksgully">Glinks Gully</option>
<option value="smartwater:hamilton:hamilton">Hamilton City</option>
<option value="bewaterwise:farnorth:kaikohengawha">Kaikohe / Ngawha</option>
<option value="bewaterwise:farnorth:kaitaia">Kaitaia</option>
<option value="bewaterwise:farnorth:kerikeriwaipapa">Kerikeri / Waipapa</option>
<option value="smartwater:waipa:kihikihi">Kihikihi</option>
<option value="bewaterwise:whangarei:mangapai">Mangapai</option>
<option value="bewaterwise:kaipara:mangawhai">Mangawhai</option>
<option value="bewaterwise:whangarei:maungakaramea">Maungakaramea</option>
<option value="bewaterwise:kaipara:maungaturoto">Maungaturoto</option>
<option value="bewaterwise:farnorth:moerewakawakawa">Moerewa / Kawakawa</option>
<option value="napiercitycouncil:napier:napier">Napier</option>
<option value="bewaterwise:farnorth:okaihau">Okaihau</option>
<option value="bewaterwise:farnorth:opononiomapere">Opononi / Omapere</option>
<option value="smartwater:waipa:pukerimu">Pukerimu</option>
<option value="bewaterwise:farnorth:rawene">Rawene</option>
<option value="bewaterwise:kaipara:ruawai">Ruawai</option>
<option value="bewaterwise:farnorth:russell">Russell</option>
<option value="smartwater:waipa:waipa">Waipa District</option>
<option value="smartwater:waikato:waikato">Waikato District</option>
<option value="bewaterwise:farnorth:waitangipaihiaopua">Waitangi / Paihia / Opua</option>
<option value="bewaterwise:whangarei:whangarei">Whangarei</option>
</options>
</parameter>
<parameter name="refreshInterval" type="integer" required="true" min="1" unit="h">
<label>Refresh Interval</label>
<default>5</default>
<description>The interval (in hours) to refresh the data.</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="alertlevel">
<item-type>Number</item-type>
<label>Alert Level</label>
<description>The alert level for the location.</description>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>