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,32 @@
<?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="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.tankerkoenig</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,190 @@
# Tankerkönig Binding
The binding uses the Tankerkönig API <https://www.tankerkoenig.de> for collecting gas price data of German gas stations.
Special thanks to the creators of Tankerkönig for providing an easy way to get data from the &lsqb;MTS-K&rsqb; (Markttransparenzstelle für Kraftstoffe).
Tankerkönig is providing this service for free, however they request to prevent overloading of their server by reducing the number of web-requests.
This binding handles those requests (minimum Refresh Interval is 10 minutes, a webserver does handle a maximum of 10 stations).
The data will be updated for each Station individually after the initialization and after each Refresh Interval for all (open) stations (Note: changing the Webservice will cause the Refresh Interval to restart).
Additionally one may select the mode Opening-Times in which only those Stations get polled which are actually open.
For a correct usage of opening times the binding needs the information if the actual day is a holiday.
Note:
While using the mode Opening-Times the channel "station_open" will NOT show "close" because during such times no update is being requested from that Station!
## Preparation
In order to use this binding one needs to prepare:
- minimal Java Version is 1.8.0_101-b13 (otherwise the https request will not produce a usable return)
- a personal API-Key
Request a free Tankerkönig API key from: <https://creativecommons.tankerkoenig.de/> (Select the tab "API-Key").
- LocationIDs of the selected gas stations
Search for the gas station IDs via the [finder tool](https://creativecommons.tankerkoenig.de/TankstellenFinder/index.html) (Select tab "Tools" -> "Tankstellenfinder").
Drag the red marker on the map to the rough location of desired gas stations.
Select the gas stations and click "Tankstellen übernehmen" on the right.
This will download a file holding the location IDs.
For example: `a7cdd9cf-b467-4aac-8eab-d662f082511e`
## Supported Things
This binding supports:
-Webservice (bridge)
-Station (thing)
## Discovery
The binding provides no discovery.
The desired Webservice and Stations must be configured manually or via a things file.
## Binding configuration
The binding has no configuration options itself, all configuration is done at 'Bridge' and 'Things' level.
## Thing configuration
The Webservice (bridge) needs to be configured with the personal API-Key, the desired Refresh Interval (the time interval between price-updates, default 60 minutes, minimum 10 minutes) and the Opening-Times mode selection (in this mode price-updates are only requested from stations that are actually open).
A single Webservice can handle up to 10 Stations.
Each Station needs to be configured with a LocationID and the Webservice to which it is linked.
## Channels
The binding introduces the channel `holiday` for the Webservice and the channels `e10`, `e5`, `diesel` and `station_open` for the Stations:
| Channel ID | Channel Description | Supported item type | Advanced |
|--------------|---------------------------------------|---------------------|----------|
| holiday | ON if today is a holiday | Switch | False |
| e10 | price of e10 | Number | False |
| e5 | price of e5 | Number | False |
| diesel | price of diesel | Number | False |
| station_open | reported opening-state of the station | Contact | False |
## Example
Note: All apikeys and locationids are only examples!
tankerkoenig.things:
```
Bridge tankerkoenig:webservice:WebserviceName "MyWebserviceName" [ apikey="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", refresh= 60, modeOpeningTime =false ] {
Thing station StationName1 "MyStationName1" @ "GasStations"[ locationid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ]
Thing station StationName2 "MyStationName2" @ "GasStations"[ locationid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ]
}
```
tankerkoenig.items:
```
Switch Station_Holidays "Today is holiday: [%s]" { channel="tankerkoenig:webservice:WebserviceName:holiday"}
Number E10_1 "E10 [%.3f €]" { channel="tankerkoenig:station:WebserviceName:StationName1:e10" }
Number E5_1 "E5 [%.3f €]" { channel="tankerkoenig:station:WebserviceName:StationName1:e5" }
Number Diesel_1 "Diesel [%.3f €]" { channel="tankerkoenig:station:WebserviceName:StationName1:diesel"}
Contact Station_Open_1 "Station is [%s]" { channel="tankerkoenig:station:WebserviceName:StationName1:station_open"}
Number E10_2 "E10 [%.3f €]" { channel="tankerkoenig:station:WebserviceName:StationName2:e10"}
Number E5_2 "E5 [%.3f €]" { channel="tankerkoenig:station:WebserviceName:StationName2:e5"}
Number Diesel_2 "Diesel [%.3f €]" { channel="tankerkoenig:station:WebserviceName:StationName2:diesel"}
Contact Station_Open_2 "Station is [%s]" { channel="tankerkoenig:station:WebserviceName:StationName2:station_open"}
```
## FAQ
-The Webservice stays OFFLINE
If only a Webservice is configured, it will remain OFFLINE until a Station is configured as well.
Each Station schedules a daily job to update detail-data, on completion of that job the Station and the Webservice will change to ONLINE.
The further price-updates for all Stations are scheduled by the Webservice using the Refresh Interval.
-The Station(s) and Webservice stay OFFLINE
Set the logging level for the binding to DEBUG (Karaf-Console command: "log:set DEBUG org.openhab.binding.tankerkoenig".
Create a new Station (in order to start the "initialize" routine).
Check the openhab.log for entries like:
```
2017-06-25 16:02:12.679 [DEBUG] [ig.internal.data.TankerkoenigService] - getTankerkoenigDetailResult IOException:
java.io.IOException: java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
......
```
This indicates a missing certificate of a certification authority (CA) in the certificate-store of the Java JDK under which openHAB is running.
In most cases, updating to the latest version of JDK solves this because the store of cacerts are maintained and updated in Java releases.
Note: You must restart openHAB after a Java update.
If you receive the error because you are running an old Linux installation which does not have the latest java-versions available in its package-repositories, you may be able to fix the issue using one of the three options below:
1.) Update the Linux system and install the latest Java version
2.) Download the most recent JDK and install it directly on to your system without using a pre-composed package
On Debian based systems one can use: http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html
3.) Update the cacerts store by importing the missing certificate
Note: Using this version, loaded certificates will expire!
If you still want to import the missing certificate, the example below may help:
Check which Java package you have installed:
```java
>> sudo dpkg -l | grep java
>> ii oracle-java8-jdk 8u65 armhf Java Platform, Standard Edition 8 Development Kit
```
Find the ca-store of your JDK
```java
>> sudo dpkg -L oracle-java8-jdk | grep cacerts
>> /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/security/cacerts
```
Check which CA has validated the certificate
Navigate to https://creativecommons.tankerkoenig.de/
Check which CA has validated the certificate
Export the certificate of the certificate authority
Import the certificate to the CA-store which you have found
```java
>> cd /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/security
>> keytool -import -keystore cacerts -alias LetsEncrypt -file ca.crt
```
The required password is "changeit".
Restart your server
-The Station(s) and Webservice go to OFFLINE after being ONLINE
Either the web-request to Tankerkönig returned a failure or no valid response was received (this could be caused by a banned API-key).
In both cases the Webservice and the Station(s) go OFFLINE.
If the Tankerkönig return indicates an error a descriptive message (in German) is added next to the OFFLINE which will be displayed on the Webservice and Station(s) pages on Paper UI.
On the next receipt of a valid message Webservice and Station(s) will go ONLINE again.
The scheduled polling of price-data is canceled in case of no valid response.
Users should check the log for any reports to solve the reason for the OFFLINE status.
In order to restart the polling a change of the Webservice has to be saved (for example a change in the Refresh Interval).
Note: If the API-key is banned by Tankerkönig, the reason has to be cleared with Tankerkönig!
-How to set the switch item for the channel holiday?
The correct usage of opening times needs the information if the actual day is a holiday.
The binding expects a switch item linked to the Webservice channel holiday.
This switch can be set either manually (only suggested for testing!) or by a rule which uses the [ephemeris action](https://www.openhab.org/docs/configuration/actions.html#ephemeris) to set that switch.
## Tankerkönig API
* <https://creativecommons.tankerkoenig.de/> (sorry, only available in German)
* &lsqb;MTS-K&rsqb;: <https://www.bundeskartellamt.de/DE/Wirtschaftsbereiche/Mineral%C3%B6l/MTS-Kraftstoffe/Verbraucher/verbraucher_node.html>
* &lsqb;openhab1-addons rules&rsqb;: <https://github.com/openhab/openhab1-addons/wiki/Samples-Rules#how-to-calculate-public-holidays>

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/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.tankerkoenig</artifactId>
<name>openHAB Add-ons :: Bundles :: Tankerkoenig Binding</name>
</project>

View File

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

View File

@@ -0,0 +1,54 @@
/**
* 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.tankerkoenig.internal;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link TankerkoenigBinding} class defines common constants, which are
* used across the whole binding.
*
* @author Dennis Dollinger - Initial contribution
*/
@NonNullByDefault
public class TankerkoenigBindingConstants {
public static final String BINDING_ID = "tankerkoenig";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_TANKSTELLE = new ThingTypeUID(BINDING_ID, "station");
public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "webservice");
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Collections.singleton(BRIDGE_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_TANKSTELLE);
// List of all Channel ids
public static final String CHANNEL_DIESEL = "diesel";
public static final String CHANNEL_E10 = "e10";
public static final String CHANNEL_E5 = "e5";
public static final String CHANNEL_STATION_OPEN = "station_open";
public static final String CHANNEL_HOLIDAY = "holiday";
// config
public static final String CONFIG_LOCATION_ID = "locationid";
public static final String CONFIG_API_KEY = "apikey";
public static final String CONFIG_REFRESH = "refresh";
public static final String CONFIG_MODE_OPENINGTIME = "modeOpeningTime";
// String used Identify unsucessful web-return
public static final String NO_VALID_RESPONSE = "No valid response from the web-request!";
}

View File

@@ -0,0 +1,63 @@
/**
* 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.tankerkoenig.internal;
import static org.openhab.binding.tankerkoenig.internal.TankerkoenigBindingConstants.*;
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.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.tankerkoenig.internal.handler.StationHandler;
import org.openhab.binding.tankerkoenig.internal.handler.WebserviceHandler;
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.Component;
/**
* The {@link TankerkoenigHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Dennis Dollinger - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.tankerkoenig")
@NonNullByDefault
public class TankerkoenigHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream
.concat(BRIDGE_THING_TYPES_UIDS.stream(), TankerkoenigBindingConstants.SUPPORTED_THING_TYPES_UIDS.stream())
.collect(Collectors.toSet()));
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(BRIDGE_THING_TYPE)) {
WebserviceHandler handler = new WebserviceHandler((Bridge) thing);
return handler;
} else if (thingTypeUID.equals(THING_TYPE_TANKSTELLE)) {
return new StationHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,105 @@
/**
* 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.tankerkoenig.internal.data;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Properties;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.tankerkoenig.internal.dto.TankerkoenigDetailResult;
import org.openhab.binding.tankerkoenig.internal.dto.TankerkoenigListResult;
import org.openhab.binding.tankerkoenig.internal.serializer.CustomTankerkoenigDetailResultDeserializer;
import org.openhab.binding.tankerkoenig.internal.serializer.CustomTankerkoenigListResultDeserializer;
import org.openhab.core.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/***
* Serivce class requesting data from tankerkoenig api and providing result objects
*
* @author Dennis Dollinger - Initial contribution
* @author Juergen Baginski - Initial contribution
*/
@NonNullByDefault
public class TankerkoenigService {
private final Logger logger = LoggerFactory.getLogger(TankerkoenigService.class);
private final Gson gson = new GsonBuilder()
.registerTypeAdapter(TankerkoenigListResult.class, new CustomTankerkoenigListResultDeserializer()).create();
private final Gson gsonDetail = new GsonBuilder()
.registerTypeAdapter(TankerkoenigDetailResult.class, new CustomTankerkoenigDetailResultDeserializer())
.create();
private static final int REQUEST_TIMEOUT = 5000;
public @Nullable TankerkoenigListResult getStationListData(String apikey, String locationIDs, String userAgent) {
return getTankerkoenigListResult(apikey, locationIDs, userAgent);
}
public @Nullable TankerkoenigDetailResult getStationDetailData(String apikey, String locationID, String userAgent) {
return getTankerkoenigDetailResult(apikey, locationID, userAgent);
}
private @Nullable String getResponseString(String apiKey, String locationIDs, String userAgent, boolean detail)
throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("https://creativecommons.tankerkoenig.de/json/");
if (detail) {
sb.append("detail.php?id=");
} else {
sb.append("prices.php?ids=");
}
sb.append(locationIDs);
sb.append("&apikey=");
sb.append(apiKey);
String url = sb.toString();
try {
Properties urlHeader = new Properties();
urlHeader.put("USER-AGENT", userAgent);
return HttpUtil.executeUrl("GET", url, urlHeader, null, "", REQUEST_TIMEOUT);
} catch (MalformedURLException e) {
logger.debug("Error in getResponseString: ", e);
return null;
}
}
private @Nullable TankerkoenigListResult getTankerkoenigListResult(String apikey, String locationIDs,
String userAgent) {
try {
String jsonData = getResponseString(apikey, locationIDs, userAgent, false);
logger.debug("json-String: {}", jsonData);
return gson.fromJson(jsonData, TankerkoenigListResult.class);
} catch (IOException e) {
logger.debug("Error in getTankerkoenigListResult: ", e);
// the return of an empty result will force the status-update OFFLINE!
return TankerkoenigListResult.emptyResult();
}
}
private @Nullable TankerkoenigDetailResult getTankerkoenigDetailResult(String apiKey, String locationID,
String userAgent) {
try {
String jsonData = getResponseString(apiKey, locationID, userAgent, true);
logger.debug("getTankerkoenigDetailResult jsonData : {}", jsonData);
return gsonDetail.fromJson(jsonData, TankerkoenigDetailResult.class);
} catch (IOException e) {
logger.debug("getTankerkoenigDetailResult IOException: ", e);
// the return of an empty result will force the status-update OFFLINE!
return TankerkoenigDetailResult.emptyResult();
}
}
}

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.tankerkoenig.internal.dto;
/**
* The {@link LittleStation} class is the representing java model for the station specific json result of the prices
* request. (LittleStation because it has nearly no other information than gas prices. Stripped down version of
* Station.java)
*
* @author Dennis Dollinger - Initial contribution
*/
public class LittleStation {
private String e5;
private String e10;
private String diesel;
private String status;
private String id;
private Boolean open;
public String getE5() {
return e5;
}
public void setE5(String e5) {
this.e5 = e5;
}
public String getE10() {
return e10;
}
public void setE10(String e10) {
this.e10 = e10;
}
public String getDiesel() {
return diesel;
}
public void setDiesel(String diesel) {
this.diesel = diesel;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getID() {
return id;
}
public void setID(String id) {
this.id = id;
}
public Boolean isOpen() {
return open;
}
public void setOpen(Boolean isOpen) {
this.open = isOpen;
}
}

View File

@@ -0,0 +1,58 @@
/**
* 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.tankerkoenig.internal.dto;
/**
* The {@link OpeningTime} class is representing single Opening Time entry from the api request (i.e one setting like
* "Montag" "09:00" "18:00")
*
* @author Jürgen Baginski - Initial contribution
*/
public class OpeningTime {
private String text;
private String start;
private String end;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getStart() {
return start;
}
public void setStart(String start) {
this.start = start;
}
public String getEnd() {
return end;
}
public void setEnd(String end) {
this.end = end;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(" ").append(this.getText()).append(" Open: ").append(this.getStart()).append(" Close: ")
.append(this.getEnd());
return sb.toString();
}
}

View File

@@ -0,0 +1,67 @@
/**
* 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.tankerkoenig.internal.dto;
/**
* The {@link OpeningTimes} class is representing all OpeningTimes entries for a station from the api request (i.e array
* of settings like "Montag" "09:00" "18:00")
* plus the boolean WholeDay (open).
*
* @author Jürgen Baginski - Initial contribution
*/
public class OpeningTimes {
private Boolean wholeDay;
private OpeningTime[] openingTimes;
private String id;
public OpeningTimes(String id, Boolean wholeDay, OpeningTime[] lopeningTimes) {
this.wholeDay = wholeDay;
this.openingTimes = lopeningTimes;
this.id = id;
}
public Boolean getWholeDay() {
return wholeDay;
}
public void setWholeDay(Boolean wholeDay) {
this.wholeDay = wholeDay;
}
public OpeningTime[] getOpeningTimes() {
return openingTimes;
}
public void setOpeningTimes(OpeningTime[] openingTimes) {
this.openingTimes = openingTimes;
}
public String getid() {
return id;
}
public void setid(String id) {
this.id = id;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("WholeDay: ").append(this.getWholeDay().toString()).append("/ Days: ");
for (OpeningTime ot : this.getOpeningTimes()) {
sb.append(ot.toString());
}
return sb.toString();
}
}

View File

@@ -0,0 +1,34 @@
/**
* 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.tankerkoenig.internal.dto;
import java.util.List;
/**
* The {@link Prices} class is the representing java model for the station specific json result of the tankerkoenig.de
* api
*
* @author Dennis Dollinger - Initial contribution
*/
public class Prices {
private List<LittleStation> stations;
public List<LittleStation> getStations() {
return stations;
}
public void setStations(List<LittleStation> stations) {
this.stations = stations;
}
}

View File

@@ -0,0 +1,116 @@
/**
* 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.tankerkoenig.internal.dto;
/**
* The {@link Station} class is the representing java model for the station specific json result of the tankerkoenig.de
* details.php
* api
*
* @author Dennis Dollinger - Initial contribution
*/
public class Station {
private String id;
private String name;
private String e5;
private String e10;
private String diesel;
private String brand;
private String street;
private String place;
private String postCode;
private Boolean open;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getE5() {
return e5;
}
public void setE5(String e5) {
this.e5 = e5;
}
public String getE10() {
return e10;
}
public void setE10(String e10) {
this.e10 = e10;
}
public String getDiesel() {
return diesel;
}
public void setDiesel(String diesel) {
this.diesel = diesel;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getPostCode() {
return postCode;
}
public void setPostCode(String postCode) {
this.postCode = postCode;
}
public Boolean isOpen() {
return open;
}
public void setOpen(Boolean isOpen) {
this.open = isOpen;
}
}

View File

@@ -0,0 +1,79 @@
/**
* 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.tankerkoenig.internal.dto;
import org.openhab.binding.tankerkoenig.internal.TankerkoenigBindingConstants;
/***
* The {@link TankerkoenigDetailResult} class is the representing java model for the json result of the tankerkoenig.de
* details request
* Actually used for OpeningTimes only.
*
* @author Dennis Dollinger - Initial contribution
* @author Jürgen Baginski - Initial contribution
*/
public class TankerkoenigDetailResult {
private boolean ok;
private boolean wholeDay;
private OpeningTimes openingTimes;
private LittleStation littleStation;
private String message;
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
public boolean iswholeDay() {
return wholeDay;
}
public void setwholeDay(boolean WholeDay) {
this.wholeDay = WholeDay;
}
public static TankerkoenigDetailResult emptyResult() {
TankerkoenigDetailResult emptyResult = new TankerkoenigDetailResult();
emptyResult.setOk(false);
emptyResult.setMessage(TankerkoenigBindingConstants.NO_VALID_RESPONSE);
return emptyResult;
}
public LittleStation getLittleStation() {
return littleStation;
}
public void setLittleStation(LittleStation littleStation) {
this.littleStation = littleStation;
}
public OpeningTimes getOpeningTimes() {
return openingTimes;
}
public void setOpeningTimes(OpeningTimes openingTimes) {
this.openingTimes = openingTimes;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,59 @@
/**
* 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.tankerkoenig.internal.dto;
import org.openhab.binding.tankerkoenig.internal.TankerkoenigBindingConstants;
/***
* The {@link TankerkoenigListResult} class is the representing java model for the json result of the tankerkoenig.de
* api
*
* @author Dennis Dollinger - Initial contribution
*/
public class TankerkoenigListResult {
private boolean ok;
private Prices prices;
private String message;
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
public Prices getPrices() {
return prices;
}
public void setPrices(Prices prices) {
this.prices = prices;
}
public static TankerkoenigListResult emptyResult() {
TankerkoenigListResult emptyResult = new TankerkoenigListResult();
emptyResult.setOk(false);
emptyResult.setMessage(TankerkoenigBindingConstants.NO_VALID_RESPONSE);
return emptyResult;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,207 @@
/**
* 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.tankerkoenig.internal.handler;
import static org.openhab.binding.tankerkoenig.internal.TankerkoenigBindingConstants.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import org.openhab.binding.tankerkoenig.internal.TankerkoenigBindingConstants;
import org.openhab.binding.tankerkoenig.internal.data.TankerkoenigService;
import org.openhab.binding.tankerkoenig.internal.dto.LittleStation;
import org.openhab.binding.tankerkoenig.internal.dto.OpeningTimes;
import org.openhab.binding.tankerkoenig.internal.dto.TankerkoenigDetailResult;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OpenClosedType;
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.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link StationHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Dennis Dollinger - Initial contribution
* @author Jürgen Baginski - Initial contribution
*/
public class StationHandler extends BaseThingHandler {
private static final Pattern IS_NUMERIC_PATTERN = Pattern.compile("\\d+(\\.\\d+)?");
private final Logger logger = LoggerFactory.getLogger(StationHandler.class);
private String apiKey;
private boolean modeOpeningTime;
private String locationID;
private OpeningTimes openingTimes;
private String userAgent;
private final TankerkoenigService service = new TankerkoenigService();
private TankerkoenigDetailResult result;
private ScheduledFuture<?> pollingJob;
public StationHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// no code needed.
}
@Override
public void initialize() {
logger.debug("Initializing Tankerkoenig handler '{}'", getThing().getUID());
Configuration config = getThing().getConfiguration();
setLocationID((String) config.get(TankerkoenigBindingConstants.CONFIG_LOCATION_ID));
setApiKey((String) config.get(TankerkoenigBindingConstants.CONFIG_API_KEY));
Bridge b = getBridge();
if (b == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
"Could not find bridge (tankerkoenig config). Did you select one?");
return;
}
WebserviceHandler handler = (WebserviceHandler) b.getHandler();
userAgent = handler.getUserAgent();
setApiKey(handler.getApiKey());
setModeOpeningTime(handler.isModeOpeningTime());
if (b.getThings().size() > 10) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"The limitation of station things for one tankerkoenig webservice (the bridge) is limited to 10.");
return;
}
updateStatus(ThingStatus.UNKNOWN);
pollingJob = scheduler.scheduleWithFixedDelay(() -> {
try {
logger.debug("Try to refresh detail data");
updateDetailData();
} catch (RuntimeException r) {
logger.debug("Caught exception in ScheduledExecutorService of TankerkoenigHandler", r);
// no status change, since in case of error in here,
// the old values for opening time will be continue to be used
}
}, 15, 86400, TimeUnit.SECONDS);// 24*60*60 = 86400, a whole day in seconds!
logger.debug("Refresh job scheduled to run every 24 hours for '{}'", getThing().getUID());
}
@Override
public void dispose() {
if (pollingJob != null) {
pollingJob.cancel(true);
}
super.dispose();
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("Bridge Status updated to {} for device: {}", bridgeStatusInfo.getStatus(), getThing().getUID());
if (bridgeStatusInfo.getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, bridgeStatusInfo.getDescription());
}
}
/***
* Updates the channels of a station item
*
* @param station
*/
public void updateData(LittleStation station) {
logger.debug("Update Tankerkoenig data '{}'", getThing().getUID());
if (IS_NUMERIC_PATTERN.matcher(station.getDiesel()).matches()) {
DecimalType diesel = new DecimalType(station.getDiesel());
updateState(CHANNEL_DIESEL, diesel);
} else {
updateState(CHANNEL_DIESEL, UnDefType.UNDEF);
}
if (IS_NUMERIC_PATTERN.matcher(station.getE10()).matches()) {
DecimalType e10 = new DecimalType(station.getE10());
updateState(CHANNEL_E10, e10);
} else {
updateState(CHANNEL_E10, UnDefType.UNDEF);
}
if (IS_NUMERIC_PATTERN.matcher(station.getE5()).matches()) {
DecimalType e5 = new DecimalType(station.getE5());
updateState(CHANNEL_E5, e5);
} else {
updateState(CHANNEL_E5, UnDefType.UNDEF);
}
updateState(CHANNEL_STATION_OPEN, (station.isOpen() ? OpenClosedType.OPEN : OpenClosedType.CLOSED));
updateStatus(ThingStatus.ONLINE);
}
/***
* Updates the detail-data from tankerkoenig api, actually only the opening times are used.
*/
public void updateDetailData() {
result = service.getStationDetailData(getApiKey(), locationID, userAgent);
if (result.isOk()) {
setOpeningTimes(result.getOpeningTimes());
LittleStation s = result.getLittleStation();
if (s == null) {
logger.debug("Station with id {} is not updated!", getLocationID());
} else {
updateData(s);
}
updateStatus(ThingStatus.ONLINE);
WebserviceHandler handler = (WebserviceHandler) getBridge().getHandler();
handler.updateStatus(ThingStatus.ONLINE);
logger.debug("updateDetailData openingTimes: {}", openingTimes);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, result.getMessage());
}
}
public String getLocationID() {
return locationID;
}
public void setLocationID(String locationID) {
this.locationID = locationID;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public boolean isModeOpeningTime() {
return modeOpeningTime;
}
public void setModeOpeningTime(boolean modeOpeningTime) {
this.modeOpeningTime = modeOpeningTime;
}
public OpeningTimes getOpeningTimes() {
return openingTimes;
}
public void setOpeningTimes(OpeningTimes openingTimes) {
this.openingTimes = openingTimes;
}
}

View File

@@ -0,0 +1,368 @@
/**
* 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.tankerkoenig.internal.handler;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.tankerkoenig.internal.TankerkoenigBindingConstants;
import org.openhab.binding.tankerkoenig.internal.data.TankerkoenigService;
import org.openhab.binding.tankerkoenig.internal.dto.LittleStation;
import org.openhab.binding.tankerkoenig.internal.dto.OpeningTime;
import org.openhab.binding.tankerkoenig.internal.dto.OpeningTimes;
import org.openhab.binding.tankerkoenig.internal.dto.TankerkoenigListResult;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
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.types.Command;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link WebserviceHandler} is responsible for handling the things (stations)
*
* @author Dennis Dollinger - Initial contribution
* @author Jürgen Baginski - Initial contribution
*/
public class WebserviceHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(WebserviceHandler.class);
private String apiKey;
private int refreshInterval;
private boolean modeOpeningTime;
private String userAgent;
private boolean isHoliday;
private final TankerkoenigService service = new TankerkoenigService();
private TankerkoenigListResult tankerkoenigListResult;
private final Map<String, LittleStation> stationMap = new HashMap<>();
private ScheduledFuture<?> pollingJob;
public WebserviceHandler(Bridge bridge) {
super(bridge);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (channelUID.getId().equals(TankerkoenigBindingConstants.CHANNEL_HOLIDAY)) {
logger.debug("HandleCommand recieved: {}", channelUID.getId());
isHoliday = (command == OnOffType.ON);
}
}
@Override
public void initialize() {
logger.debug("Initialize Bridge");
Configuration config = getThing().getConfiguration();
setApiKey((String) config.get(TankerkoenigBindingConstants.CONFIG_API_KEY));
setRefreshInterval(((BigDecimal) config.get(TankerkoenigBindingConstants.CONFIG_REFRESH)).intValue());
setModeOpeningTime((boolean) config.get(TankerkoenigBindingConstants.CONFIG_MODE_OPENINGTIME));
// set the UserAgent, this string is used by TankerkoenigService
// to set a custom UserAgent for the WebRequest as specifically requested by Tankerkoening.de!
StringBuilder sb = new StringBuilder();
sb.append("openHAB, Tankerkoenig-Binding Version ");
Version version = FrameworkUtil.getBundle(getClass()).getVersion();
sb.append(version.toString());
userAgent = sb.toString();
updateStatus(ThingStatus.UNKNOWN);
int pollingPeriod = getRefreshInterval();
pollingJob = scheduler.scheduleWithFixedDelay(() -> {
logger.debug("Try to refresh data");
try {
updateStationData();
updateStationThings();
} catch (RuntimeException r) {
logger.debug("Caught exception in ScheduledExecutorService of BridgeHandler. RuntimeException: ", r);
updateStatus(ThingStatus.OFFLINE);
}
}, pollingPeriod, pollingPeriod, TimeUnit.MINUTES);
logger.debug("Refresh job scheduled to run every {} min. for '{}'", pollingPeriod, getThing().getUID());
}
@Override
public void dispose() {
if (pollingJob != null) {
pollingJob.cancel(true);
}
}
@Override
public void updateStatus(ThingStatus status) {
updateStatus(status, ThingStatusDetail.NONE, null);
}
/***
* Updates the data from tankerkoenig api (no update on things)
*/
public void updateStationData() {
// Get data
try {
String locationIDsString = "";
if (modeOpeningTime) {
logger.debug("Opening times are used");
locationIDsString = generateOpenLocationIDsString();
} else {
logger.debug("No opening times are used");
locationIDsString = generateLocationIDsString();
}
if (locationIDsString.isEmpty()) {
logger.debug("No tankstellen id's found. Nothing to update");
return;
}
TankerkoenigListResult result = service.getStationListData(getApiKey(), locationIDsString, userAgent);
if (!result.isOk()) {
// two possibel reasons for result.isOK=false
// A-tankerkoenig returns false on a web-request
// in this case the field "message" holds information for the reason.
// B-the web-request does not return a valid json-string,
// in this case an emptyReturn object is created with the message "No valid response from the
// web-request!"
// in both cases the Webservice and the Station(s) will go OFFLINE
// only in case A the pollingJob gets canceled!
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, result.getMessage());
// if the Bridge goes OFFLINE, all connected Stations will go OFFLINE as well.
// The bridge reports its statusUpdate and the things react using the bridgeStatusChanged-Method!
// Only if the message is NOT "No valid response from the web-request!" the scheduled job gets stopped!
if (!result.getMessage().equals(TankerkoenigBindingConstants.NO_VALID_RESPONSE)) {
pollingJob.cancel(true);
}
} else {
updateStatus(ThingStatus.ONLINE);
setTankerkoenigListResult(result);
stationMap.clear();
for (LittleStation station : result.getPrices().getStations()) {
station.setOpen("open".equals(station.getStatus()));
stationMap.put(station.getID(), station);
}
logger.debug("UpdateStationData: tankstellenList.size {}", stationMap.size());
}
} catch (ParseException e) {
logger.error("ParseException: ", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
}
}
/***
* Updates all registered station with new data
*/
public void updateStationThings() {
logger.debug("UpdateStationThings: getThing().getThings().size {}", getThing().getThings().size());
for (Thing thing : getThing().getThings()) {
StationHandler tkh = (StationHandler) thing.getHandler();
LittleStation s = stationMap.get(tkh.getLocationID());
if (s == null) {
logger.debug("Station with id {} is not updated!", tkh.getLocationID());
} else {
tkh.updateData(s);
}
}
}
/***
* Generates a comma separated string with all station id's
*
* @return
*/
private String generateLocationIDsString() {
StringBuilder sb = new StringBuilder();
for (Thing thing : getThing().getThings()) {
StationHandler tkh = (StationHandler) thing.getHandler();
if (sb.length() > 0) {
sb.append(",");
}
sb.append(tkh.getLocationID());
}
return sb.toString();
}
/***
* Generates a comma separated string of all open station id's
* calculated using the data stored in opentimesList
* The settings in the section "override" from the json detail response are NOT used!
*
* @return String
* @throws ParseException
*/
private String generateOpenLocationIDsString() throws ParseException {
StringBuilder sb = new StringBuilder();
LocalDate today = LocalDate.now();
for (Thing thing : getThing().getThings()) {
String start = "00:00";
String ende = "00:00";
StationHandler tkh = (StationHandler) thing.getHandler();
Boolean foundIt = false;
OpeningTimes oTimes = tkh.getOpeningTimes();
// oTimes could be NULL, assume wholeDay open in this case!
if (oTimes != null) {
if (oTimes.getWholeDay()) {
// WholeDay open, use this ID!
foundIt = true;
logger.debug("Found a setting for WholeDay.");
// "start" and "ende" are set manually!
start = "00:00";
ende = "23:59";
} else {
OpeningTime[] o = oTimes.getOpeningTimes();
logger.debug("o.length: {}", o.length);
int i = 0;
do {
logger.debug("Checking opening time i: {}", i);
String day = o[i].getText();
String open = o[i].getStart();
String close = o[i].getEnd();
DayOfWeek weekday = today.getDayOfWeek();
logger.debug("Checking day: {}", day);
logger.debug("Todays weekday: {}", weekday);
if (isHoliday) {
weekday = DayOfWeek.SUNDAY;
logger.debug("Today is a holiday using : {}", weekday);
}
// if Daily, further checking not needed!
if (day.contains("täglich")) {
logger.debug("Found a setting for daily opening times.");
foundIt = true;
} else {
switch (weekday) {
case MONDAY:
if ((day.contains("Werktags")) || (day.contains("Mo"))) {
logger.debug("Found a setting which is valid for today (Monday).");
foundIt = true;
}
break;
case TUESDAY:
if ((day.contains("Werktags")) || (day.contains("Di")) || (day.contains("Mo-Fr"))) {
logger.debug("Found a setting which is valid for today (Tuesday).");
foundIt = true;
}
break;
case WEDNESDAY:
if ((day.contains("Werktags")) || (day.contains("Mi")) || (day.contains("Mo-Fr"))) {
logger.debug("Found a setting which is valid for today (Wednesday).");
foundIt = true;
}
break;
case THURSDAY:
if ((day.contains("Werktags")) || (day.contains("Do")) || (day.contains("Mo-Fr"))) {
logger.debug("Found a setting which is valid for today (Thursday).");
foundIt = true;
}
break;
case FRIDAY:
if ((day.contains("Werktags")) || (day.contains("Fr"))) {
logger.debug("Found a setting which is valid for today (Fryday).");
foundIt = true;
}
break;
case SATURDAY:
if ((day.contains("Wochendende")) || (day.contains("Sa"))) {
logger.debug("Found a setting which is valid for today (Saturday).");
foundIt = true;
}
break;
case SUNDAY:
if ((day.contains("Wochenende")) || (day.contains("So"))) {
logger.debug("Found a setting which is valid for today (Sunday).");
foundIt = true;
}
break;
}
if (foundIt) {
start = open;
ende = close;
break;
}
}
i = i + 1;
} while (i < o.length);
}
} else {
// no OpeningTimes found, assuming WholeDay open!
foundIt = true;
logger.debug("No OpeningTimes are found, assuming WholeDay.");
// "start" and "ende" are set manually!
start = "00:00";
ende = "23:59";
}
LocalTime opening = LocalTime.parse(start);
LocalTime closing = LocalTime.parse(ende);
LocalTime now = LocalTime.now();
if (!opening.equals(closing)) {
// Tankerkoenig.de does update the status "open" every 4 minutes
// due to this the status "open" could be sent up to 4 minutes after the published opening time
// therefore the first update is called 4 minutes after opening time!
opening = opening.plusMinutes(4);
}
if ((opening.equals(closing)) || ((now.isAfter(opening) & (now.isBefore(closing))))) {
logger.debug("Now is within opening times for today.");
if (sb.length() > 0) {
sb.append(",");
}
sb.append(tkh.getLocationID());
}
}
return sb.toString();
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public int getRefreshInterval() {
return refreshInterval;
}
public void setRefreshInterval(int refreshInterval) {
this.refreshInterval = refreshInterval;
}
public TankerkoenigListResult getTankerkoenigListResult() {
return tankerkoenigListResult;
}
public void setTankerkoenigListResult(TankerkoenigListResult tankerkoenigListResult) {
this.tankerkoenigListResult = tankerkoenigListResult;
}
public boolean isModeOpeningTime() {
return modeOpeningTime;
}
public void setModeOpeningTime(boolean modeOpeningTime) {
this.modeOpeningTime = modeOpeningTime;
}
public String getUserAgent() {
return userAgent;
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.tankerkoenig.internal.serializer;
import java.lang.reflect.Type;
import org.openhab.binding.tankerkoenig.internal.dto.LittleStation;
import org.openhab.binding.tankerkoenig.internal.dto.OpeningTime;
import org.openhab.binding.tankerkoenig.internal.dto.OpeningTimes;
import org.openhab.binding.tankerkoenig.internal.dto.TankerkoenigDetailResult;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
/***
* Custom Deserializer for the detail result of tankerkoenigs api response
*
* @author Jürgen Baginski - Initial contribution
*/
public class CustomTankerkoenigDetailResultDeserializer implements JsonDeserializer<TankerkoenigDetailResult> {
@Override
public TankerkoenigDetailResult deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final Boolean isOK = jsonObject.get("ok").getAsBoolean();
TankerkoenigDetailResult result = new TankerkoenigDetailResult();
if (isOK) {
final JsonObject jsonStation = jsonObject.get("station").getAsJsonObject();
final Boolean isWholeDay = jsonStation.get("wholeDay").getAsBoolean();
final LittleStation littleStation = new LittleStation();
if (!jsonStation.get("e10").isJsonNull()) {
final String e10 = jsonStation.get("e10").getAsString();
littleStation.setE10(e10);
}
if (!jsonStation.get("e5").isJsonNull()) {
final String e5 = jsonStation.get("e5").getAsString();
littleStation.setE5(e5);
}
if (!jsonStation.get("diesel").isJsonNull()) {
final String diesel = jsonStation.get("diesel").getAsString();
littleStation.setDiesel(diesel);
}
final Boolean isOpen = jsonStation.get("isOpen").getAsBoolean();
final String stationID = jsonStation.get("id").getAsString();
OpeningTime[] openingTime = context.deserialize(jsonStation.get("openingTimes"), OpeningTime[].class);
littleStation.setOpen(isOpen);
littleStation.setID(stationID);
final OpeningTimes openingTimes = new OpeningTimes(stationID, isWholeDay, openingTime);
result.setLittleStation(littleStation);
result.setOk(isOK);
result.setwholeDay(isWholeDay);
result.setOpeningTimes(openingTimes);
} else {
final String message = jsonObject.get("message").getAsString();
result.setOk(isOK);
result.setMessage(message);
}
return result;
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.tankerkoenig.internal.serializer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.openhab.binding.tankerkoenig.internal.dto.LittleStation;
import org.openhab.binding.tankerkoenig.internal.dto.Prices;
import org.openhab.binding.tankerkoenig.internal.dto.TankerkoenigListResult;
import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
/***
* Custom Deserializer fopr the list result of tankerkoenigs api response
*
* @author Dennis Dollinger - Initial contribution
*/
public class CustomTankerkoenigListResultDeserializer implements JsonDeserializer<TankerkoenigListResult> {
private final Gson gson = new Gson();
@Override
public TankerkoenigListResult deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final Boolean isOK = jsonObject.get("ok").getAsBoolean();
TankerkoenigListResult result = new TankerkoenigListResult();
if (isOK) {
result.setOk(jsonObject.get("ok").getAsBoolean());
JsonObject jsonPrices = jsonObject.get("prices").getAsJsonObject();
Set<Entry<String, JsonElement>> objects = jsonPrices.entrySet();
Prices p = new Prices();
result.setPrices(p);
List<LittleStation> list = new ArrayList<>();
for (Entry<String, JsonElement> entry : objects) {
JsonElement jsonElement = entry.getValue();
LittleStation station = gson.fromJson(jsonElement, LittleStation.class);
station.setID(entry.getKey());
list.add(station);
}
result.getPrices().setStations(list);
} else {
result.setOk(jsonObject.get("ok").getAsBoolean());
result.setMessage(jsonObject.get("message").getAsString());
}
return result;
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="tankerkoenig" 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>Tankerkönig Binding</name>
<description>The Tankerkönig Binding allows to poll fuel prices of German gas stations by using the Tankerkoenig.de
API.</description>
<author>Dennis Dollinger / Jürgen Baginski</author>
</binding:binding>

View File

@@ -0,0 +1,29 @@
# binding
binding.tankerkoenig.name = Tankerkönig Binding
binding.tankerkoenig.description = Das Tankerkönig Binding ermöglicht es über die Tankerkoenig.de API Spritpreise von deutschen Tankstellen abzurufen.
# thing types
thing-type.tankerkoenig.webservice.label = Tankerkönig Webservice
thing-type.tankerkoenig.webservice.description = Der Tankerkönig Werbservice ermöglicht es die Spritpreise von 1 bis 10 Tankstellen abzufragen.
thing-type.config.tankerkoenig.webservice.apikey.label=API-Key
thing-type.config.tankerkoenig.webservice.apikey.description=Tankerkönig API-Key. Der Schlüssel ist auf der Tankerkönig Webseite erhältlich.
thing-type.config.tankerkoenig.webservice.refresh.label=Aktualisierungsintervall
thing-type.config.tankerkoenig.webservice.refresh.description=Spezifiziert das Aktualisierungsintervall in Minuten. Minimum 10 Minuten.
thing-type.config.tankerkoenig.webservice.modeOpeningTime.label=Öffnungszeiten
thing-type.config.tankerkoenig.webservice.modeOpeningTime.description=Im Mode Öffnungszeiten werden nur die zur Zeit geöffneten Tankstellen abgefragt.
thing-type.tankerkoenig.station.label=Tankstelle
thing-type.tankerkoenig.station.description=Stellt die Informationen zu den E5-, E10-, und Diesel-Preisen einer Tankstelle bereit.
thing-type.config.tankerkoenig.station.locationid.label=Tankstellen-ID
thing-type.config.tankerkoenig.station.locationid.description=Tankstellen-ID. Die ID ist auf der Tankerkönig Webseite erhältlich.
# channel types
channel-type.tankerkoenig.diesel.label = Diesel
channel-type.tankerkoenig.e5.label = E5
channel-type.tankerkoenig.e10.label = E10
channel-type.tankerkoenig.station_open.label = Öffnungs-Status
channel-type.tankerkoenig.holiday.label = Feiertag
channel-type.tankerkoenig.diesel.description = Diesel-Preis
channel-type.tankerkoenig.e5.description= E5-Preis
channel-type.tankerkoenig.e10.description = E10-Preis
channel-type.tankerkoenig.station_open.description = Gemeldeter Öffnungs-Status
channel-type.tankerkoenig.holiday.description = ON, wenn Heute ein Feiertag ist

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tankerkoenig"
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="station">
<supported-bridge-type-refs>
<bridge-type-ref id="webservice"/>
</supported-bridge-type-refs>
<label>Gas-Station</label>
<description>Provides the prices of gas types E5-, E10- and Diesel of that station and if that station reports as
opened.</description>
<channels>
<channel id="diesel" typeId="diesel"/>
<channel id="e10" typeId="e10"/>
<channel id="e5" typeId="e5"/>
<channel id="station_open" typeId="station_open"/>
</channels>
<config-description>
<parameter name="locationid" type="text" required="true">
<label>Gas-Station-ID</label>
<description>Fuel-Station-ID. You can get the required ID for your Gas-Station via the Tankerkönig website.</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="diesel">
<item-type>Number</item-type>
<label>Diesel</label>
<description>price for diesel</description>
<state pattern="%.3f €" readOnly="true"></state>
</channel-type>
<channel-type id="e10">
<item-type>Number</item-type>
<label>E10</label>
<description>price for E10</description>
<state pattern="%.3f €" readOnly="true"></state>
</channel-type>
<channel-type id="e5">
<item-type>Number</item-type>
<label>E5</label>
<description>price for E5</description>
<state pattern="%.3f €" readOnly="true"></state>
</channel-type>
<channel-type id="station_open">
<item-type>Contact</item-type>
<label>Opening State</label>
<description>The reported opening-state of that Station.</description>
<state pattern="%s" readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tankerkoenig"
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="webservice">
<label>Tankerkönig Webservice</label>
<description>The Tankerkönig Webservice can handle 1 to 10 gas stations.</description>
<channels>
<channel id="holiday" typeId="holiday"/>
</channels>
<config-description>
<parameter name="apikey" type="text" required="true">
<label>API-Key</label>
<description>API-Key. Necessary registration on the Tankerkönig website.</description>
<default></default>
</parameter>
<parameter name="refresh" type="integer" required="true" min="10">
<label>Refresh Time</label>
<description>Sets the refresh time. Minimum is 10 minutes.</description>
<default>60</default>
</parameter>
<parameter name="modeOpeningTime" type="boolean">
<label>Opening Time</label>
<description>In mode Opening Time only those gas stations are polled that are actually open.</description>
<default>false</default>
</parameter>
</config-description>
</bridge-type>
<channel-type id="holiday">
<item-type>Switch</item-type>
<label>Holiday</label>
<description>ON if today is a holiday.</description>
</channel-type>
</thing:thing-descriptions>