added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
49
bundles/org.openhab.binding.coronastats/.classpath
Normal file
49
bundles/org.openhab.binding.coronastats/.classpath
Normal 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>
|
||||
23
bundles/org.openhab.binding.coronastats/.project
Normal file
23
bundles/org.openhab.binding.coronastats/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.coronastats</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>
|
||||
13
bundles/org.openhab.binding.coronastats/NOTICE
Normal file
13
bundles/org.openhab.binding.coronastats/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
127
bundles/org.openhab.binding.coronastats/README.md
Normal file
127
bundles/org.openhab.binding.coronastats/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# CoronaStats Binding
|
||||
|
||||
This binding provides the statistic about cases of COVID-19 from the website https://corona-stats.online/.
|
||||
|
||||
|
||||
## Supported Things
|
||||
|
||||
This binding supports a `world` thing, which polls the dataset in an adjustable interval as a bridge and provides the statistics for the whole world.
|
||||
The `country` thing, representing the statistics for a specified country.
|
||||
|
||||
## Discovery
|
||||
|
||||
This binding adds a default `world` thing to the Inbox.
|
||||
This can be used as bridge for country things you may add manually.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### World
|
||||
|
||||
| Parameter | Default | Required | Description |
|
||||
| --------- | :-----: | :------: | ---------------------------------------------------------------------------------------- |
|
||||
| `refresh` | 30 | no | Define the interval for polling the data from website in minutes. Minimum is 15 minutes. |
|
||||
|
||||
### Country
|
||||
|
||||
| Parameter | Default | Required | Description |
|
||||
| ------------- | :-----: | :------: | ------------------------------------------------- |
|
||||
| `countryCode` | - | yes | 2-letter code for the country you want to display |
|
||||
|
||||
For the correct 2-letter country code have a look at the website https://corona-stats.online/
|
||||
|
||||
## Channels
|
||||
|
||||
### World and Country
|
||||
|
||||
| channels | type | description |
|
||||
| -------------- | -------------------- | ---------------------------------------------- |
|
||||
| `cases` | Number:Dimensionless | Total cases |
|
||||
| `today_cases` | Number:Dimensionless | Increase of total cases today |
|
||||
| `deaths` | Number:Dimensionless | Deaths |
|
||||
| `today_deaths` | Number:Dimensionless | Increase of deaths |
|
||||
| `recovered` | Number:Dimensionless | Recovered cases |
|
||||
| `active` | Number:Dimensionless | Active cases |
|
||||
| `critical` | Number:Dimensionless | Critical cases |
|
||||
| `tests` | Number:Dimensionless | Count of reported tests (`country` thing only) |
|
||||
| `updated` | Number:Dimensionless | Data last update time (`country` thing only) |
|
||||
|
||||
## Full Example
|
||||
|
||||
### Things
|
||||
|
||||
```
|
||||
Bridge coronastats:world:stats "Corona Stats World" @ "Corona" [refresh=15] {
|
||||
Thing country usa "Corona Stats USA" @ "Corona" [countryCode="US"]
|
||||
Thing country germany "Corona Stats Germany" @ "Corona" [countryCode="DE"]
|
||||
Thing country austria "Corona Stats Austria" @ "Corona" [countryCode="AT"]
|
||||
Thing country italy "Corona Stats Italy" @ "Corona" [countryCode="IT"]
|
||||
Thing country spain "Corona Stats Spain" @ "Corona" [countryCode="ES"]
|
||||
Thing country uk "Corona Stats United Kingdom" @ "Corona" [countryCode="GB"]
|
||||
}
|
||||
```
|
||||
|
||||
### Items
|
||||
|
||||
```
|
||||
Number:Dimensionless coronaCasesWorld "Total Cases World [%,d]"
|
||||
{channel="coronastats:world:stats:cases"}
|
||||
|
||||
Number:Dimensionless coronaDeathsWorld "Deaths World [%,d]"
|
||||
{channel="coronastats:world:stats:deaths"}
|
||||
|
||||
Number:Dimensionless coronaRecoveredWorld "Recovered Cases World [%,d]"
|
||||
{channel="coronastats:world:stats:recovered"}
|
||||
|
||||
Number:Dimensionless coronaActiveWorld "Active Cases World [%,d]"
|
||||
{channel="coronastats:world:stats:active"}
|
||||
|
||||
Number:Dimensionless coronaCriticalWorld "Critical Cases World [%,d]"
|
||||
{channel="coronastats:world:stats:critical"}
|
||||
|
||||
Number:Dimensionless coronaCasesUSA "Total Cases USA [%,d]"
|
||||
{channel="coronastats:country:stats:usa:cases"}
|
||||
|
||||
Number:Dimensionless coronaDeathsUSA "Deaths USA [%,d]"
|
||||
{channel="coronastats:country:stats:usa:deaths"}
|
||||
|
||||
Number:Dimensionless coronaRecoveredUSA "Recovered Cases USA [%,d]"
|
||||
{channel="coronastats:country:stats:usa:recovered"}
|
||||
|
||||
Number:Dimensionless coronaActiveUSA "Active Cases USA [%,d]"
|
||||
{channel="coronastats:country:stats:usa:active"}
|
||||
|
||||
Number:Dimensionless coronaCriticalUSA "Critical Cases USA [%,d]"
|
||||
{channel="coronastats:country:stats:usa:critical"}
|
||||
|
||||
Number:Dimensionless coronaTestsUSA "Tests USA [%d]"
|
||||
{channel="coronastats:country:stats:usa:cases"}
|
||||
|
||||
DateTime coronaUpdatedUSA "Updated USA [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]"
|
||||
{channel="coronastats:country:stats:usa:updated"}
|
||||
```
|
||||
|
||||
### Sitemap
|
||||
|
||||
```
|
||||
Text label="Corona" {
|
||||
Frame label="World" {
|
||||
Text item=coronaCasesWorld
|
||||
Text item=coronaActiveWorld
|
||||
Text item=coronaRecoveredWorld
|
||||
Text item=coronaDeathsWorld
|
||||
Text item=coronaCriticalWorld
|
||||
Text item=coronaTestUSA
|
||||
}
|
||||
|
||||
Frame label="USA" {
|
||||
Text item=coronaCasesUSA
|
||||
Text item=coronaActiveUSA
|
||||
Text item=coronaRecoveredUSA
|
||||
Text item=coronaDeathsUSA
|
||||
Text item=coronaCriticalUSA
|
||||
Text item=coronaTestsUSA
|
||||
Text item=coronaUpdatedUSA
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
17
bundles/org.openhab.binding.coronastats/pom.xml
Normal file
17
bundles/org.openhab.binding.coronastats/pom.xml
Normal 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/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.coronastats</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: CoronaStats Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.coronastats-${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-coronastats" description="CoronaStats Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.coronastats/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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.coronastats.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsBindingConstants {
|
||||
public static final String BINDING_ID = "coronastats";
|
||||
|
||||
// World
|
||||
public static final ThingTypeUID THING_TYPE_WORLD = new ThingTypeUID(BINDING_ID, "world");
|
||||
public static final String STATS = "stats";
|
||||
public static final String WORLD_LABEL = "Corona Statistics (World)";
|
||||
|
||||
// Country
|
||||
public static final ThingTypeUID THING_TYPE_COUNTRY = new ThingTypeUID(BINDING_ID, "country");
|
||||
|
||||
// @formatter:off
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS =
|
||||
Collections.unmodifiableSet(Stream
|
||||
.of(THING_TYPE_WORLD, THING_TYPE_COUNTRY)
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
// @formatter:on
|
||||
|
||||
// Properties country
|
||||
public static final String PROPERTY_COUNTRY = "country";
|
||||
|
||||
// Channels world/country
|
||||
public static final String CHANNEL_CASES = "cases";
|
||||
public static final String CHANNEL_NEW_CASES = "today_cases";
|
||||
public static final String CHANNEL_DEATHS = "deaths";
|
||||
public static final String CHANNEL_NEW_DEATHS = "today_deaths";
|
||||
public static final String CHANNEL_RECOVERED = "recovered";
|
||||
public static final String CHANNEL_ACTIVE = "active";
|
||||
public static final String CHANNEL_CRITICAL = "critical";
|
||||
public static final String CHANNEL_TESTS = "tests";
|
||||
public static final String CHANNEL_UPDATED = "updated";
|
||||
}
|
||||
@@ -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.coronastats.internal;
|
||||
|
||||
import static org.openhab.binding.coronastats.internal.CoronaStatsBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.coronastats.internal.handler.CoronaStatsCountryHandler;
|
||||
import org.openhab.binding.coronastats.internal.handler.CoronaStatsWorldHandler;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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 CoronaStatsHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.coronastats", service = ThingHandlerFactory.class)
|
||||
public class CoronaStatsHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Activate
|
||||
public CoronaStatsHandlerFactory(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_WORLD.equals(thingTypeUID)) {
|
||||
return new CoronaStatsWorldHandler((Bridge) thing, httpClient);
|
||||
} else if (THING_TYPE_COUNTRY.equals(thingTypeUID)) {
|
||||
return new CoronaStatsCountryHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.coronastats.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsPollingException} class is the exception for all polling errors.
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsPollingException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CoronaStatsPollingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CoronaStatsPollingException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.coronastats.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Configuration for the {@link CoronaStatsCountryHandler}
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsCountryConfiguration {
|
||||
private String countryCode = "";
|
||||
|
||||
public String getCountryCode() {
|
||||
return countryCode.toUpperCase();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return !"".equals(countryCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.coronastats.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Configuration for the {@link CoronaStatsWorldHandler}
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsWorldConfiguration {
|
||||
public int refresh = 30;
|
||||
|
||||
public boolean isValid() {
|
||||
return refresh >= 15;
|
||||
}
|
||||
}
|
||||
@@ -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.coronastats.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.coronastats.internal.CoronaStatsBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
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.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsDiscoveryService} create a default world thing.
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.coronastats")
|
||||
public class CoronaStatsDiscoveryService extends AbstractDiscoveryService {
|
||||
private static final ThingUID WORLD_THING_UID = new ThingUID(THING_TYPE_WORLD, STATS);
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 2;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(CoronaStatsDiscoveryService.class);
|
||||
|
||||
public CoronaStatsDiscoveryService() throws IllegalArgumentException {
|
||||
super(SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Manual CoronaStats discovery scan.");
|
||||
addWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
logger.debug("Background CoronaStats discovery scan.");
|
||||
addWorld();
|
||||
}
|
||||
|
||||
private void addWorld() {
|
||||
// @formatter:off
|
||||
DiscoveryResult world = DiscoveryResultBuilder
|
||||
.create(WORLD_THING_UID)
|
||||
.withLabel(WORLD_LABEL)
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
thingDiscovered(world);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.coronastats.internal.dto;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStats} class is internal CoronaStats structure.
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStats {
|
||||
@SerializedName("data")
|
||||
private @Nullable Set<CoronaStatsCountry> countries;
|
||||
|
||||
@SerializedName("worldStats")
|
||||
private @Nullable CoronaStatsWorld world;
|
||||
|
||||
public @Nullable CoronaStatsCountry getCountry(String countryCodeKey) {
|
||||
final Set<CoronaStatsCountry> localCountries = countries;
|
||||
if (localCountries != null) {
|
||||
for (CoronaStatsCountry country : localCountries) {
|
||||
if (country.getCountryCode().equals(countryCodeKey)) {
|
||||
return country;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public @Nullable CoronaStatsWorld getWorld() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.coronastats.internal.dto;
|
||||
|
||||
import static org.openhab.binding.coronastats.internal.CoronaStatsBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
import tec.uom.se.AbstractUnit;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsCountry} class holds the internal data representation of each Country
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsCases {
|
||||
private int cases = -1;
|
||||
private int todayCases = -1;
|
||||
private int deaths = -1;
|
||||
private int todayDeaths = -1;
|
||||
private int recovered = -1;
|
||||
private int active = -1;
|
||||
private int critical = -1;
|
||||
|
||||
protected Map<String, State> getCaseChannelsStateMap() {
|
||||
Map<String, State> map = new HashMap<>();
|
||||
|
||||
map.put(CHANNEL_CASES, parseToState(cases));
|
||||
map.put(CHANNEL_NEW_CASES, parseToState(todayCases));
|
||||
map.put(CHANNEL_DEATHS, parseToState(deaths));
|
||||
map.put(CHANNEL_NEW_DEATHS, parseToState(todayDeaths));
|
||||
map.put(CHANNEL_RECOVERED, parseToState(recovered));
|
||||
map.put(CHANNEL_ACTIVE, parseToState(active));
|
||||
map.put(CHANNEL_CRITICAL, parseToState(critical));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected State parseToState(int count) {
|
||||
if (count == -1) {
|
||||
return UnDefType.NULL;
|
||||
} else {
|
||||
return new QuantityType<Dimensionless>(count, AbstractUnit.ONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.coronastats.internal.dto;
|
||||
|
||||
import static org.openhab.binding.coronastats.internal.CoronaStatsBindingConstants.*;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsCountry} class holds the internal data representation of each Country
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsCountry extends CoronaStatsCases {
|
||||
private String country = "";
|
||||
private String countryCode = "";
|
||||
private int tests = -1;
|
||||
private long updated = -1;
|
||||
|
||||
public String getCountryCode() {
|
||||
return countryCode;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put(PROPERTY_COUNTRY, country);
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public Map<String, State> getChannelsStateMap() {
|
||||
Map<String, State> map = super.getCaseChannelsStateMap();
|
||||
|
||||
map.put(CHANNEL_TESTS, parseToState(tests));
|
||||
|
||||
if (updated == -1) {
|
||||
map.put(CHANNEL_UPDATED, UnDefType.NULL);
|
||||
} else {
|
||||
Date date = new Date(updated);
|
||||
ZonedDateTime zoned = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
|
||||
map.put(CHANNEL_UPDATED, new DateTimeType(zoned));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
}
|
||||
@@ -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.coronastats.internal.dto;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsWorld} class holds the internal data representation for world stats
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsWorld extends CoronaStatsCases {
|
||||
public Map<String, State> getChannelsStateMap() {
|
||||
return Collections.unmodifiableMap(super.getCaseChannelsStateMap());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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.coronastats.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.coronastats.internal.config.CoronaStatsCountryConfiguration;
|
||||
import org.openhab.binding.coronastats.internal.dto.CoronaStats;
|
||||
import org.openhab.binding.coronastats.internal.dto.CoronaStatsCountry;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsCountryHandler} is the handler for country thing
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsCountryHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(CoronaStatsCountryHandler.class);
|
||||
|
||||
private CoronaStatsCountryConfiguration thingConfig = new CoronaStatsCountryConfiguration();
|
||||
|
||||
public CoronaStatsCountryHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
thingConfig = getConfigAs(CoronaStatsCountryConfiguration.class);
|
||||
logger.debug("Initializing Corona Stats country handler for country code {}", thingConfig.getCountryCode());
|
||||
|
||||
if (thingConfig.isValid()) {
|
||||
CoronaStatsWorldHandler handler = getBridgeHandler();
|
||||
if (handler == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Bridge handler missing");
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No valid country code given.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("CoronaStats country handler disposes.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
CoronaStatsWorldHandler handler = getBridgeHandler();
|
||||
if (handler != null) {
|
||||
CoronaStats coronaStats = handler.getCoronaStats();
|
||||
if (coronaStats != null) {
|
||||
notifyOnUpdate(coronaStats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable CoronaStatsWorldHandler getBridgeHandler() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof CoronaStatsWorldHandler) {
|
||||
return (CoronaStatsWorldHandler) handler;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void notifyOnUpdate(CoronaStats coronaStats) {
|
||||
CoronaStatsCountry country = coronaStats.getCountry(thingConfig.getCountryCode());
|
||||
if (country == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Country not found");
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
updateProperties(country.getProperties());
|
||||
|
||||
country.getChannelsStateMap().forEach(this::updateState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* 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.coronastats.internal.handler;
|
||||
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
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.HttpResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.coronastats.internal.CoronaStatsPollingException;
|
||||
import org.openhab.binding.coronastats.internal.config.CoronaStatsWorldConfiguration;
|
||||
import org.openhab.binding.coronastats.internal.dto.CoronaStats;
|
||||
import org.openhab.binding.coronastats.internal.dto.CoronaStatsWorld;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link CoronaStatsWorldHandler} is the handler for bridge thing
|
||||
*
|
||||
* @author Johannes Ott - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CoronaStatsWorldHandler extends BaseBridgeHandler {
|
||||
private static final String CORONASTATS_URL = "https://corona-stats.online/?format=json";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(CoronaStatsWorldHandler.class);
|
||||
|
||||
private CoronaStatsWorldConfiguration worldConfig = new CoronaStatsWorldConfiguration();
|
||||
private @Nullable ScheduledFuture<?> pollingJob;
|
||||
private @Nullable CoronaStats coronaStats;
|
||||
private final Set<CoronaStatsCountryHandler> countryListeners = ConcurrentHashMap.newKeySet();
|
||||
private final HttpClient client;
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public CoronaStatsWorldHandler(Bridge bridge, HttpClient client) {
|
||||
super(bridge);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
final CoronaStats localCoronaStats = coronaStats;
|
||||
if (localCoronaStats != null) {
|
||||
notifyOnUpdate(localCoronaStats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing Corona Stats bridge handler");
|
||||
worldConfig = getConfigAs(CoronaStatsWorldConfiguration.class);
|
||||
|
||||
if (worldConfig.isValid()) {
|
||||
startPolling();
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Refresh interval has to be at least 15 minutes.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Handler disposed.");
|
||||
stopPolling();
|
||||
}
|
||||
|
||||
private void startPolling() {
|
||||
final ScheduledFuture<?> localPollingJob = this.pollingJob;
|
||||
if (localPollingJob == null || localPollingJob.isCancelled()) {
|
||||
logger.debug("Start polling.");
|
||||
pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, worldConfig.refresh, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopPolling() {
|
||||
final ScheduledFuture<?> localPollingJob = this.pollingJob;
|
||||
if (localPollingJob != null && !localPollingJob.isCancelled()) {
|
||||
logger.debug("Stop polling.");
|
||||
localPollingJob.cancel(true);
|
||||
pollingJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void poll() {
|
||||
logger.debug("Polling");
|
||||
requestRefresh().handle((resultCoronaStats, pollException) -> {
|
||||
if (resultCoronaStats == null) {
|
||||
if (pollException == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
pollException.getMessage());
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
notifyOnUpdate(resultCoronaStats);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<@Nullable CoronaStats> requestRefresh() {
|
||||
CompletableFuture<@Nullable CoronaStats> f = new CompletableFuture<>();
|
||||
Request request = client.newRequest(URI.create(CORONASTATS_URL));
|
||||
|
||||
request.method(HttpMethod.GET).timeout(2000, TimeUnit.SECONDS).send(new BufferingResponseListener() {
|
||||
@NonNullByDefault({})
|
||||
@Override
|
||||
public void onComplete(Result result) {
|
||||
final HttpResponse response = (HttpResponse) result.getResponse();
|
||||
if (result.getFailure() != null) {
|
||||
Throwable e = result.getFailure();
|
||||
if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
||||
f.completeExceptionally(new CoronaStatsPollingException("Request timeout", e));
|
||||
} else {
|
||||
f.completeExceptionally(new CoronaStatsPollingException("Request failed", e));
|
||||
}
|
||||
} else if (response.getStatus() != 200) {
|
||||
f.completeExceptionally(new CoronaStatsPollingException(getContentAsString()));
|
||||
} else {
|
||||
try {
|
||||
CoronaStats coronaStatsJSON = gson.fromJson(getContentAsString(), CoronaStats.class);
|
||||
f.complete(coronaStatsJSON);
|
||||
} catch (JsonSyntaxException parseException) {
|
||||
logger.error("Parsing failed: {}", parseException.getMessage());
|
||||
f.completeExceptionally(new CoronaStatsPollingException("Parsing of response failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
|
||||
if (childHandler instanceof CoronaStatsCountryHandler) {
|
||||
logger.debug("Register thing listener.");
|
||||
final CoronaStatsCountryHandler listener = (CoronaStatsCountryHandler) childHandler;
|
||||
if (countryListeners.add(listener)) {
|
||||
final CoronaStats localCoronaStats = coronaStats;
|
||||
if (localCoronaStats != null) {
|
||||
listener.notifyOnUpdate(localCoronaStats);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Tried to add listener {} but it was already present. This is probably an error.",
|
||||
childHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
|
||||
if (childHandler instanceof CoronaStatsCountryHandler) {
|
||||
logger.debug("Unregister thing listener.");
|
||||
if (!countryListeners.remove((CoronaStatsCountryHandler) childHandler)) {
|
||||
logger.warn("Tried to remove listener {} but it was not registered. This is probably an error.",
|
||||
childHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyOnUpdate(@Nullable CoronaStats newCoronaStats) {
|
||||
if (newCoronaStats != null) {
|
||||
coronaStats = newCoronaStats;
|
||||
|
||||
CoronaStatsWorld world = newCoronaStats.getWorld();
|
||||
if (world == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "World stats not found");
|
||||
return;
|
||||
}
|
||||
|
||||
world.getChannelsStateMap().forEach(this::updateState);
|
||||
countryListeners.forEach(listener -> listener.notifyOnUpdate(newCoronaStats));
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable CoronaStats getCoronaStats() {
|
||||
return coronaStats;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="coronastats" 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>CoronaStats Binding</name>
|
||||
<description>This is a binding for accessing data from https://corona-stats.online/ website.</description>
|
||||
<author>Johannes Ott</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="coronastats"
|
||||
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="cases">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Total Cases</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="today_cases">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>New Cases</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="deaths">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Total Deaths</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="today_deaths">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>New Deaths</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="recovered">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Recovered</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="active">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Active</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="critical">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Critical</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tests">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Tests</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="updated">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Updated</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="coronastats"
|
||||
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="country">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="world"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Corona Statistics (Country)</label>
|
||||
<description>Corona statistics for a specific country</description>
|
||||
|
||||
<channels>
|
||||
<channel id="cases" typeId="cases"/>
|
||||
<channel id="today_cases" typeId="today_cases"/>
|
||||
<channel id="deaths" typeId="deaths"/>
|
||||
<channel id="today_deaths" typeId="today_deaths"/>
|
||||
<channel id="recovered" typeId="recovered"/>
|
||||
<channel id="active" typeId="active"/>
|
||||
<channel id="critical" typeId="critical"/>
|
||||
<channel id="tests" typeId="tests"/>
|
||||
<channel id="updated" typeId="updated"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="country"/>
|
||||
</properties>
|
||||
|
||||
<config-description>
|
||||
<parameter name="countryCode" type="text" required="true">
|
||||
<label>Country Code</label>
|
||||
<description>2-letter Country Code</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="coronastats"
|
||||
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">
|
||||
|
||||
<bridge-type id="world">
|
||||
<label>Corona Statistics (World)</label>
|
||||
<description>Bridge for accessing data from https://corona-stats.online/ website and representing world statistics.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="cases" typeId="cases"/>
|
||||
<channel id="today_cases" typeId="today_cases"/>
|
||||
<channel id="deaths" typeId="deaths"/>
|
||||
<channel id="today_deaths" typeId="today_deaths"/>
|
||||
<channel id="recovered" typeId="recovered"/>
|
||||
<channel id="active" typeId="active"/>
|
||||
<channel id="critical" typeId="critical"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="refresh" type="integer" unit="min" min="15">
|
||||
<default>30</default>
|
||||
<label>Refresh Interval</label>
|
||||
<description>Time between two API requests in minutes. Minimum 15 minutes.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</bridge-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user