added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.enturno/.classpath
Normal file
32
bundles/org.openhab.binding.enturno/.classpath
Normal 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>
|
||||
23
bundles/org.openhab.binding.enturno/.project
Normal file
23
bundles/org.openhab.binding.enturno/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.enturno</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>
|
||||
48
bundles/org.openhab.binding.enturno/CONTRIBUTE.md
Normal file
48
bundles/org.openhab.binding.enturno/CONTRIBUTE.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# How can you contribute?
|
||||
|
||||
This binding is meant to get Norwegian public transport real-time (estimated) data from [Entur.no API](https://developer.entur.org/content/journey-planner-0).
|
||||
|
||||
It runs GraphQL-API query against the service.
|
||||
|
||||
Entur provides an [IDE for the API](https://api.entur.org/doc/shamash-journeyplanner/) (use query from GraphQL request example below as a start point) Ctrl+Space gives hints of valid values
|
||||
|
||||
There are several possibilities to get and process data from endpoints that entur.no provides. One of possible examples is to get all departures for all lines from specified stop place (all directions) or even specified quay (specified direction). Those are not supported yet so feel free to extend functionality of this binding.
|
||||
|
||||
## GraphQL request example
|
||||
|
||||
```
|
||||
{
|
||||
stopPlace(id: "NSR:StopPlace:30848") {
|
||||
id
|
||||
name
|
||||
transportMode
|
||||
estimatedCalls(startTime:"2019-04-06T10:00:00+01:00" timeRange: 86400, numberOfDepartures: 400) {
|
||||
realtime
|
||||
aimedArrivalTime
|
||||
aimedDepartureTime
|
||||
expectedArrivalTime
|
||||
expectedDepartureTime
|
||||
date
|
||||
forBoarding
|
||||
forAlighting
|
||||
destinationDisplay {
|
||||
frontText
|
||||
}
|
||||
quay {
|
||||
id
|
||||
publicCode
|
||||
}
|
||||
serviceJourney {
|
||||
journeyPattern {
|
||||
line {
|
||||
id
|
||||
name
|
||||
transportMode
|
||||
publicCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
13
bundles/org.openhab.binding.enturno/NOTICE
Normal file
13
bundles/org.openhab.binding.enturno/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
|
||||
97
bundles/org.openhab.binding.enturno/README.md
Normal file
97
bundles/org.openhab.binding.enturno/README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# EnturNo Binding
|
||||
|
||||
This binding gets Norwegian public transport real-time (estimated) data from the [Entur.org API](https://developer.entur.org/pages-intro-overview).
|
||||
|
||||
## Supported Things
|
||||
|
||||
As for now, binding supports only one thing `linestop`.
|
||||
It can change in the future as [entur.org](https://developer.entur.org) exposes API for access of different type public transport data, for example: journey planing, stop information etc.
|
||||
|
||||
### Entur Timetable
|
||||
|
||||
Entur timetable provides information about departures for chosen line/service of public transport in Norway and chosen stop place.
|
||||
It contains informationabout stop place (id, name, transport mode) and real-time departures from that place.
|
||||
**It is worth noting that binding is thought to be primarily used for busdepartures (can work for other supported by [entur.org](https://developer.entur.org/pages-intro-overview) transport types).
|
||||
Two Direction channel groups are consequence of that assumption.
|
||||
That will say that usually for stop place of a given name there are two bus stops for same line going in opposite directions.**
|
||||
Each **Direction** channel group contains information about direction,line code, 5 coming departures, and whether given departure time is real-time (estimated) or not.
|
||||
|
||||
## Discovery
|
||||
|
||||
Since thing needs to be explicitly configured for stop id and line, no auto discovery is available.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### Entur Timetable
|
||||
|
||||
| Parameter | Description |
|
||||
|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| stopPlaceId (Stop code) | Unique id of stop place that can be get from [en-tur.no](https://en-tur.no) after selecting bus stop. Information will be displayed in link. Example: <https://en-tur.no/nearby-stop-place-detail?id=NSR:StopPlace:30848> stopPlaceId is **NSR:StopPlace:30848** in this case|
|
||||
| lineCode (Line code) | Code (name or numeber) of line used by public transport provider. Examples: 3, 3E, 4, 21 |
|
||||
|
||||
## Channels
|
||||
|
||||
### Stop Place
|
||||
|
||||
| Channel Group ID | Channel ID | Item Type | Description |
|
||||
|------------------|-----------------|-----------|-------------------------------------------------------------|
|
||||
| stopPlace | id | String | Id of the stop place. |
|
||||
| stopPlace | name | String | Name of the stop place. |
|
||||
| stopPlace | transportMode | String | Type of transport served from bus stop bus/train/plane etc. |
|
||||
|
||||
### Line Direction
|
||||
|
||||
| Channel Group ID | Channel ID | Item Type | Description |
|
||||
|-------------------|---------------------------------------------------------------------------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| direction | lineCode | String | Code (usually number) of the public transport line. |
|
||||
| direction | frontDisplayText | String | Text of front display of the public transport line (usually direction) |
|
||||
| direction | departure01, departure02, departure03, departure04, departure05 | DateTime | Times of next five departures. |
|
||||
| direction | estimatedFlag01, estimatedFlag02, estimatedFlag03, estimatedFlag04, estimatedFlag05 | String | Values (true/false) saying that corresponding departure is real-time (estimated - true) or departure from timetable. Values (true/false) can be parsed to boolean. |
|
||||
|
||||
## Full Example
|
||||
|
||||
### Things
|
||||
|
||||
demo.things
|
||||
|
||||
```java
|
||||
Thing enturno:linestop:7e693fff "Småstrandgaten line nr 2" [stopPlaceId="NSR:StopPlace:30848", lineCode="2"]
|
||||
```
|
||||
|
||||
### Items
|
||||
|
||||
demo.items
|
||||
|
||||
```java
|
||||
// Stop place
|
||||
String StopId "StopId" {channel="enturno:linestop:7e693fff:stopPlace#id"}
|
||||
String StopPlaceName "Stop Place [%s]" {channel="enturno:linestop:7e693fff:stopPlace#name"}
|
||||
String LineCode "Line [%s]" {channel="enturno:linestop:7e693fff:Direction01#lineCode"}
|
||||
String TransportMode "TransportMode [%s]" {channel="enturno:linestop:7e693fff:stopPlace#transportMode"}
|
||||
|
||||
// Direction01
|
||||
String Direction01_FrontDisplay "Direction01 front display [%s]" {channel="enturno:linestop:7e693fff:Direction01#frontDisplayText"}
|
||||
DateTime RealTime_Direction01_Time1 "Departure01 time" {channel="enturno:linestop:7e693fff:Direction01#departure01"}
|
||||
DateTime RealTime_Direction01_Time2 "Departure02 time" {channel="enturno:linestop:7e693fff:Direction01#departure02"}
|
||||
DateTime RealTime_Direction01_Time3 "Departure03 time" {channel="enturno:linestop:7e693fff:Direction01#departure03"}
|
||||
DateTime RealTime_Direction01_Time4 "Departure04 time" {channel="enturno:linestop:7e693fff:Direction01#departure04"}
|
||||
DateTime RealTime_Direction01_Time5 "Departure05 time" {channel="enturno:linestop:7e693fff:Direction01#departure05"}
|
||||
String RealTime_Direction01_IsReal1 "Departure01 is real-time" {channel="enturno:linestop:7e693fff:Direction01#estimatedFlag01"}
|
||||
String RealTime_Direction01_IsReal2 "Departure02 is real-time" {channel="enturno:linestop:7e693fff:Direction01#estimatedFlag02"}
|
||||
String RealTime_Direction01_IsReal3 "Departure03 is real-time" {channel="enturno:linestop:7e693fff:Direction01#estimatedFlag03"}
|
||||
String RealTime_Direction01_IsReal4 "Departure04 is real-time" {channel="enturno:linestop:7e693fff:Direction01#estimatedFlag04"}
|
||||
String RealTime_Direction01_IsReal5 "Departure05 is real-time" {channel="enturno:linestop:7e693fff:Direction01#estimatedFlag05"}
|
||||
|
||||
//Direction02
|
||||
String Direction02_FrontDisplay "Direction02 front display [%s]" {channel="enturno:linestop:7e693fff:Direction02#frontDisplayText"}
|
||||
DateTime RealTime_Direction02_Time1 "Departure01 time" {channel="enturno:linestop:7e693fff:Direction02#departure01"}
|
||||
DateTime RealTime_Direction02_Time2 "Departure02 time" {channel="enturno:linestop:7e693fff:Direction02#departure02"}
|
||||
DateTime RealTime_Direction02_Time3 "Departure03 time" {channel="enturno:linestop:7e693fff:Direction02#departure03"}
|
||||
DateTime RealTime_Direction02_Time4 "Departure04 time" {channel="enturno:linestop:7e693fff:Direction02#departure04"}
|
||||
DateTime RealTime_Direction02_Time5 "Departure05 time" {channel="enturno:linestop:7e693fff:Direction02#departure05"}
|
||||
String RealTime_Direction02_IsReal1 "Departure01 is real-time" {channel="enturno:linestop:7e693fff:Direction02#estimatedFlag01"}
|
||||
String RealTime_Direction02_IsReal2 "Departure02 is real-time" {channel="enturno:linestop:7e693fff:Direction02#estimatedFlag02"}
|
||||
String RealTime_Direction02_IsReal3 "Departure03 is real-time" {channel="enturno:linestop:7e693fff:Direction02#estimatedFlag03"}
|
||||
String RealTime_Direction02_IsReal4 "Departure04 is real-time" {channel="enturno:linestop:7e693fff:Direction02#estimatedFlag04"}
|
||||
String RealTime_Direction02_IsReal5 "Departure05 is real-time" {channel="enturno:linestop:7e693fff:Direction02#estimatedFlag05"}
|
||||
```
|
||||
17
bundles/org.openhab.binding.enturno/pom.xml
Normal file
17
bundles/org.openhab.binding.enturno/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.enturno</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: EnturNo Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.enturno-${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-enturno" description="Enturno Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.enturno/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.enturno.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link EnturNoBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnturNoBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "enturno";
|
||||
|
||||
public static final String TIME_ZONE = "Europe/Oslo";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID LINESTOP = new ThingTypeUID(BINDING_ID, "linestop");
|
||||
|
||||
// List of all channel groups
|
||||
public static final String CHANNEL_GROUP_STOP_PLACE = "stopPlace";
|
||||
public static final String CHANNEL_GROUP_DIRECTION_1 = "Direction01";
|
||||
public static final String CHANNEL_GROUP_DIRECTION_2 = "Direction02";
|
||||
|
||||
// List of all channels
|
||||
public static final String CHANNEL_STOP_ID = "id";
|
||||
public static final String CHANNEL_STOP_NAME = "name";
|
||||
public static final String CHANNEL_STOP_TRANSPORT_MODE = "transportMode";
|
||||
public static final String CHANNEL_LINE_CODE = "lineCode";
|
||||
public static final String CHANNEL_DEPARTURE_01 = "departure01";
|
||||
public static final String CHANNEL_DEPARTURE_02 = "departure02";
|
||||
public static final String CHANNEL_DEPARTURE_03 = "departure03";
|
||||
public static final String CHANNEL_DEPARTURE_04 = "departure04";
|
||||
public static final String CHANNEL_DEPARTURE_05 = "departure05";
|
||||
public static final String ESTIMATED_FLAG_01 = "estimatedFlag01";
|
||||
public static final String ESTIMATED_FLAG_02 = "estimatedFlag02";
|
||||
public static final String ESTIMATED_FLAG_03 = "estimatedFlag03";
|
||||
public static final String ESTIMATED_FLAG_04 = "estimatedFlag04";
|
||||
public static final String ESTIMATED_FLAG_05 = "estimatedFlag05";
|
||||
public static final String CHANNEL_FRONT_DISPLAY = "frontDisplayText";
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.enturno.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link EnturNoConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnturNoConfiguration {
|
||||
|
||||
public @Nullable String stopPlaceId;
|
||||
|
||||
public @Nullable String getStopPlaceId() {
|
||||
return stopPlaceId;
|
||||
}
|
||||
|
||||
public void setStopPlaceId(String stopPlaceId) {
|
||||
this.stopPlaceId = stopPlaceId;
|
||||
}
|
||||
|
||||
public @Nullable String lineCode;
|
||||
|
||||
public @Nullable String getLineCode() {
|
||||
return lineCode;
|
||||
}
|
||||
|
||||
public void setLineCode(String lineCode) {
|
||||
this.lineCode = lineCode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* 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.enturno.internal;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.enturno.internal.connection.EnturCommunicationException;
|
||||
import org.openhab.binding.enturno.internal.connection.EnturConfigurationException;
|
||||
import org.openhab.binding.enturno.internal.connection.EnturNoConnection;
|
||||
import org.openhab.binding.enturno.internal.model.simplified.DisplayData;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
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.type.ChannelKind;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link EnturNoHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnturNoHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EnturNoHandler.class);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private @NonNullByDefault({}) EnturNoConfiguration config;
|
||||
|
||||
private @NonNullByDefault({}) EnturNoConnection connection;
|
||||
|
||||
private static final long INITIAL_DELAY_IN_SECONDS = 15;
|
||||
|
||||
private static final long REFRESH_INTERVAL_IN_SECONDS = 30;
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
private @Nullable String stopId;
|
||||
|
||||
private List<DisplayData> processedData = new ArrayList<>();
|
||||
|
||||
public EnturNoHandler(Thing thing, HttpClient httpClient) {
|
||||
super(thing);
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannel(channelUID);
|
||||
} else {
|
||||
logger.debug("Entur binding is a read-only binding and cannot handle command '{}'.", command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initialize Entur EnturTimeTable API handler '{}'.", getThing().getUID());
|
||||
config = getConfigAs(EnturNoConfiguration.class);
|
||||
stopId = config.getStopPlaceId();
|
||||
|
||||
logger.debug("Stop place id: {}", stopId);
|
||||
boolean configValid = true;
|
||||
if (StringUtils.trimToNull(stopId) == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-missing-stopId");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
logger.debug("Line code: {}", config.getLineCode());
|
||||
if (StringUtils.trimToNull(config.getLineCode()) == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-missing-lineCode");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
connection = new EnturNoConnection(this, httpClient);
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
if (refreshJob == null || refreshJob.isCancelled()) {
|
||||
logger.debug("Start refresh job at interval {} sec.", REFRESH_INTERVAL_IN_SECONDS);
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::updateThing, INITIAL_DELAY_IN_SECONDS,
|
||||
REFRESH_INTERVAL_IN_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Dispose Entur real-time timetable API handler '{}'.", getThing().getUID());
|
||||
if (refreshJob != null && !refreshJob.isCancelled()) {
|
||||
logger.debug("Stop refresh job.");
|
||||
if (refreshJob.cancel(true)) {
|
||||
refreshJob = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnturNoConfiguration getEnturNoConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
private void updateThing() {
|
||||
ThingStatus status = ThingStatus.OFFLINE;
|
||||
if (connection != null) {
|
||||
logger.trace("Updating data");
|
||||
updateData(connection);
|
||||
status = thing.getStatus();
|
||||
} else {
|
||||
logger.debug("Cannot update real-time data of thing '{}' as connection is null.", thing.getUID());
|
||||
status = ThingStatus.OFFLINE;
|
||||
}
|
||||
|
||||
updateStatus(status);
|
||||
}
|
||||
|
||||
public void updateData(EnturNoConnection connection) {
|
||||
try {
|
||||
if (requestData(connection)) {
|
||||
updateChannels();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (EnturCommunicationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getLocalizedMessage());
|
||||
} catch (EnturConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requestData(EnturNoConnection connection)
|
||||
throws EnturConfigurationException, EnturCommunicationException {
|
||||
logger.debug("Update real-time data of thing '{}'.", getThing().getUID());
|
||||
try {
|
||||
processedData = connection.getEnturTimeTable(stopId, config.getLineCode());
|
||||
|
||||
return true;
|
||||
} catch (JsonSyntaxException e) {
|
||||
logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChannels() {
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
ChannelUID channelUID = channel.getUID();
|
||||
if (ChannelKind.STATE.equals(channel.getKind()) && channelUID.isInGroup() && channelUID.getGroupId() != null
|
||||
&& isLinked(channelUID)) {
|
||||
updateChannel(channelUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChannel(ChannelUID channelUID) {
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
logger.trace("Channel group id: {}", channelGroupId);
|
||||
if (channelGroupId != null) {
|
||||
switch (channelGroupId) {
|
||||
case EnturNoBindingConstants.CHANNEL_GROUP_STOP_PLACE:
|
||||
updateStopPlaceChannel(channelUID);
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_GROUP_DIRECTION_1:
|
||||
updateDirectionChannel(channelUID, 0);
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_GROUP_DIRECTION_2:
|
||||
updateDirectionChannel(channelUID, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDirectionChannel(ChannelUID channelUID, int i) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
logger.trace("Channel id: {}, Channel group id: {}", channelId, channelGroupId);
|
||||
if (processedData.size() > i) {
|
||||
State state = UnDefType.UNDEF;
|
||||
List<String> departures = processedData.get(i).departures;
|
||||
List<String> estimatedFlags = processedData.get(i).estimatedFlags;
|
||||
switch (channelId) {
|
||||
case EnturNoBindingConstants.CHANNEL_DEPARTURE_01:
|
||||
state = departures.size() > 0 ? getDateTimeTypeState(departures.get(0)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_DEPARTURE_02:
|
||||
state = departures.size() > 1 ? getDateTimeTypeState(departures.get(1)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_DEPARTURE_03:
|
||||
state = departures.size() > 2 ? getDateTimeTypeState(departures.get(2)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_DEPARTURE_04:
|
||||
state = departures.size() > 3 ? getDateTimeTypeState(departures.get(3)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_DEPARTURE_05:
|
||||
state = departures.size() > 4 ? getDateTimeTypeState(departures.get(4)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.ESTIMATED_FLAG_01:
|
||||
state = estimatedFlags.size() > 0 ? getStringTypeState(estimatedFlags.get(0)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.ESTIMATED_FLAG_02:
|
||||
state = estimatedFlags.size() > 1 ? getStringTypeState(estimatedFlags.get(1)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.ESTIMATED_FLAG_03:
|
||||
state = estimatedFlags.size() > 2 ? getStringTypeState(estimatedFlags.get(2)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.ESTIMATED_FLAG_04:
|
||||
state = estimatedFlags.size() > 3 ? getStringTypeState(estimatedFlags.get(3)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.ESTIMATED_FLAG_05:
|
||||
state = estimatedFlags.size() > 4 ? getStringTypeState(estimatedFlags.get(4)) : state;
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_LINE_CODE:
|
||||
state = getStringTypeState(processedData.get(i).lineCode);
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_FRONT_DISPLAY:
|
||||
state = getStringTypeState(processedData.get(i).frontText);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No real-time data available to update channel '{}' of group '{}'.", channelId,
|
||||
channelGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last Entur data retrieved.
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
*/
|
||||
private void updateStopPlaceChannel(ChannelUID channelUID) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
if (!processedData.isEmpty()) {
|
||||
State state = UnDefType.UNDEF;
|
||||
switch (channelId) {
|
||||
case EnturNoBindingConstants.CHANNEL_STOP_ID:
|
||||
state = getStringTypeState(processedData.get(0).stopPlaceId);
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_STOP_NAME:
|
||||
state = getStringTypeState(processedData.get(0).stopName);
|
||||
break;
|
||||
case EnturNoBindingConstants.CHANNEL_STOP_TRANSPORT_MODE:
|
||||
state = getStringTypeState(processedData.get(0).transportMode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No real-time data available to update channel '{}' of group '{}'.", channelId,
|
||||
channelGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
private State getDateTimeTypeState(@Nullable String value) {
|
||||
return (value == null) ? UnDefType.UNDEF
|
||||
: new DateTimeType(ZonedDateTime.parse(value, DateTimeFormatter.ISO_DATE_TIME)
|
||||
.withZoneSameInstant(ZoneId.of(EnturNoBindingConstants.TIME_ZONE)));
|
||||
}
|
||||
|
||||
private State getStringTypeState(@Nullable String value) {
|
||||
return (value == null) ? UnDefType.UNDEF : new StringType(value);
|
||||
}
|
||||
}
|
||||
@@ -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.enturno.internal;
|
||||
|
||||
import static org.openhab.binding.enturno.internal.EnturNoBindingConstants.LINESTOP;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link EnturNoHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.enturno", service = ThingHandlerFactory.class)
|
||||
public class EnturNoHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(LINESTOP);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Activate
|
||||
public EnturNoHandlerFactory(@Reference final 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 (LINESTOP.equals(thingTypeUID)) {
|
||||
return new EnturNoHandler(thing, httpClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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.enturno.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link EnturCommunicationException} is a communication exception for the connections to Entur API.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnturCommunicationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EnturCommunicationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EnturCommunicationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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.enturno.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link EnturConfigurationException} is a configuration exception for the connections to Entur API.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnturConfigurationException extends IllegalArgumentException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EnturConfigurationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EnturConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public EnturConfigurationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* 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.enturno.internal.connection;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
import static org.eclipse.jetty.http.HttpMethod.POST;
|
||||
import static org.eclipse.jetty.http.HttpStatus.*;
|
||||
import static org.openhab.binding.enturno.internal.EnturNoBindingConstants.TIME_ZONE;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.openhab.binding.enturno.internal.EnturNoConfiguration;
|
||||
import org.openhab.binding.enturno.internal.EnturNoHandler;
|
||||
import org.openhab.binding.enturno.internal.model.EnturJsonData;
|
||||
import org.openhab.binding.enturno.internal.model.estimated.EstimatedCalls;
|
||||
import org.openhab.binding.enturno.internal.model.simplified.DisplayData;
|
||||
import org.openhab.binding.enturno.internal.model.stopplace.StopPlace;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link EnturNoConnection} is responsible for handling connection to Entur.no API
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnturNoConnection {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EnturNoConnection.class);
|
||||
private static final String REQUEST_BODY = "realtime_request.graphql";
|
||||
private static final String PROPERTY_MESSAGE = "message";
|
||||
private static final String CONTENT_TYPE = "application/graphql";
|
||||
private static final String REQUIRED_CLIENT_NAME_HEADER = "ET-Client-Name";
|
||||
private static final String REQUIRED_CLIENT_NAME = "openHAB-enturnobinding";
|
||||
|
||||
private static final String PARAM_STOPID = "stopid";
|
||||
private static final String PARAM_START_DATE_TIME = "startDateTime";
|
||||
|
||||
private static final String REALTIME_URL = "https://api.entur.io/journey-planner/v2/graphql";
|
||||
|
||||
private final EnturNoHandler handler;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private final JsonParser parser = new JsonParser();
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public EnturNoConnection(EnturNoHandler handler, HttpClient httpClient) {
|
||||
this.handler = handler;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the real-time timetable for specified line and stop place
|
||||
*
|
||||
* @param stopPlaceId stop place id see https://en-tur.no
|
||||
* @return the real-time timetable
|
||||
* @throws JsonSyntaxException
|
||||
* @throws EnturCommunicationException
|
||||
* @throws EnturConfigurationException
|
||||
*/
|
||||
public synchronized List<DisplayData> getEnturTimeTable(@Nullable String stopPlaceId, @Nullable String lineCode)
|
||||
throws JsonSyntaxException, EnturConfigurationException, EnturCommunicationException {
|
||||
if (StringUtils.isBlank(stopPlaceId)) {
|
||||
throw new EnturConfigurationException("Stop place id cannot be empty or null");
|
||||
} else if (lineCode == null || StringUtils.isBlank(lineCode)) {
|
||||
throw new EnturConfigurationException("Line code cannot be empty or null");
|
||||
}
|
||||
|
||||
Map<String, String> params = getRequestParams(handler.getEnturNoConfiguration());
|
||||
|
||||
EnturJsonData enturJsonData = gson.fromJson(getResponse(REALTIME_URL, params), EnturJsonData.class);
|
||||
|
||||
if (enturJsonData == null) {
|
||||
throw new EnturCommunicationException("Error when deserializing response to EnturJsonData.class");
|
||||
}
|
||||
|
||||
return processData(enturJsonData.data.stopPlace, lineCode);
|
||||
}
|
||||
|
||||
private Map<String, String> getRequestParams(EnturNoConfiguration config) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put(PARAM_STOPID, StringUtils.trimToEmpty(config.getStopPlaceId()));
|
||||
params.put(PARAM_START_DATE_TIME, StringUtils.trimToEmpty(LocalDateTime.now(ZoneId.of(TIME_ZONE)).toString()));
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private String getResponse(String url, Map<String, String> params) {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Entur request: URL = '{}', graphQL parameters -> startTime = '{}', stopId = '{}'",
|
||||
REALTIME_URL, params.get(PARAM_START_DATE_TIME), params.get(PARAM_STOPID));
|
||||
}
|
||||
|
||||
Request request = httpClient.newRequest(url);
|
||||
request.method(POST);
|
||||
request.timeout(10, TimeUnit.SECONDS);
|
||||
request.header(HttpHeader.CONTENT_TYPE, CONTENT_TYPE);
|
||||
request.header(REQUIRED_CLIENT_NAME_HEADER, REQUIRED_CLIENT_NAME);
|
||||
request.content(new StringContentProvider(getRequestBody(params)));
|
||||
|
||||
logger.trace("Request body: {}", getRequestBody(params));
|
||||
|
||||
ContentResponse contentResponse = request.send();
|
||||
|
||||
int httpStatus = contentResponse.getStatus();
|
||||
String content = contentResponse.getContentAsString();
|
||||
String errorMessage = StringUtils.EMPTY;
|
||||
logger.trace("Entur response: status = {}, content = '{}'", httpStatus, content);
|
||||
switch (httpStatus) {
|
||||
case OK_200:
|
||||
return content;
|
||||
case BAD_REQUEST_400:
|
||||
case NOT_FOUND_404:
|
||||
errorMessage = getErrorMessage(content);
|
||||
logger.debug("Entur server responded with status code {}: {}", httpStatus, errorMessage);
|
||||
throw new EnturConfigurationException(errorMessage);
|
||||
default:
|
||||
errorMessage = getErrorMessage(content);
|
||||
logger.debug("Entur server responded with status code {}: {}", httpStatus, errorMessage);
|
||||
throw new EnturCommunicationException(errorMessage);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
String errorMessage = e.getLocalizedMessage();
|
||||
logger.debug("Exception occurred during execution: {}", errorMessage, e);
|
||||
throw new EnturCommunicationException(errorMessage, e);
|
||||
} catch (InterruptedException | TimeoutException | IOException e) {
|
||||
logger.debug("Exception occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
throw new EnturCommunicationException(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getErrorMessage(String response) {
|
||||
JsonObject jsonResponse = parser.parse(response).getAsJsonObject();
|
||||
if (jsonResponse.has(PROPERTY_MESSAGE)) {
|
||||
return jsonResponse.get(PROPERTY_MESSAGE).getAsString();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private String getRequestBody(Map<String, String> params) throws IOException {
|
||||
try (InputStream inputStream = EnturNoConnection.class.getClassLoader().getResourceAsStream(REQUEST_BODY);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
String json = bufferedReader.lines().collect(Collectors.joining("\n"));
|
||||
|
||||
return json.replaceAll("\\{stopPlaceId}", "" + params.get(PARAM_STOPID)).replaceAll("\\{startDateTime}",
|
||||
"" + params.get(PARAM_START_DATE_TIME));
|
||||
}
|
||||
}
|
||||
|
||||
private List<DisplayData> processData(StopPlace stopPlace, String lineCode) {
|
||||
Map<String, List<EstimatedCalls>> departures = stopPlace.estimatedCalls.stream()
|
||||
.filter(call -> StringUtils.equalsIgnoreCase(
|
||||
StringUtils.trimToEmpty(call.serviceJourney.journeyPattern.line.publicCode),
|
||||
StringUtils.trimToEmpty(lineCode)))
|
||||
.collect(groupingBy(call -> call.quay.id));
|
||||
|
||||
List<DisplayData> processedData = new ArrayList<>();
|
||||
if (departures.keySet().size() > 0) {
|
||||
DisplayData processedData01 = getDisplayData(stopPlace, departures, 0);
|
||||
processedData.add(processedData01);
|
||||
}
|
||||
|
||||
if (departures.keySet().size() > 1) {
|
||||
DisplayData processedData02 = getDisplayData(stopPlace, departures, 1);
|
||||
processedData.add(processedData02);
|
||||
}
|
||||
|
||||
return processedData;
|
||||
}
|
||||
|
||||
private DisplayData getDisplayData(StopPlace stopPlace, Map<String, List<EstimatedCalls>> departures,
|
||||
int quayIndex) {
|
||||
List<String> keys = new ArrayList<>(departures.keySet());
|
||||
DisplayData processedData = new DisplayData();
|
||||
List<EstimatedCalls> quayCalls = departures.get(keys.get(quayIndex));
|
||||
List<String> departureTimes = quayCalls.stream().map(eq -> eq.expectedDepartureTime).map(this::getIsoDateTime)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String> estimatedFlags = quayCalls.stream().map(es -> es.realtime).collect(Collectors.toList());
|
||||
|
||||
if (quayCalls.size() > quayIndex) {
|
||||
String lineCode = quayCalls.get(0).serviceJourney.journeyPattern.line.publicCode;
|
||||
String frontText = quayCalls.get(0).destinationDisplay.frontText;
|
||||
processedData.lineCode = lineCode;
|
||||
processedData.frontText = frontText;
|
||||
processedData.departures = departureTimes;
|
||||
processedData.estimatedFlags = estimatedFlags;
|
||||
}
|
||||
|
||||
processedData.stopPlaceId = stopPlace.id;
|
||||
processedData.stopName = stopPlace.name;
|
||||
processedData.transportMode = stopPlace.transportMode;
|
||||
return processedData;
|
||||
}
|
||||
|
||||
private String getIsoDateTime(String dateTimeWithoutColonInZone) {
|
||||
String dateTime = StringUtils.substringBeforeLast(dateTimeWithoutColonInZone, "+");
|
||||
String offset = StringUtils.substringAfterLast(dateTimeWithoutColonInZone, "+");
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
return builder.append(dateTime).append("+").append(StringUtils.substring(offset, 0, 2)).append(":00")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.enturno.internal.model;
|
||||
|
||||
import org.openhab.binding.enturno.internal.model.stopplace.StopPlace;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Data} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class Data {
|
||||
public StopPlace stopPlace;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.enturno.internal.model;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Data} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class EnturData {
|
||||
public Data data;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.enturno.internal.model;
|
||||
|
||||
/**
|
||||
* {@link EnturJsonData} is a root level class to holding reference of data generated from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class EnturJsonData {
|
||||
public Data data;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.estimated;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link DestinationDisplay} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class DestinationDisplay {
|
||||
public String frontText;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.estimated;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link EstimatedCalls} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class EstimatedCalls {
|
||||
public String aimedArrivalTime;
|
||||
|
||||
public String date;
|
||||
|
||||
public String realtime;
|
||||
|
||||
public String expectedDepartureTime;
|
||||
|
||||
public String forAlighting;
|
||||
|
||||
public DestinationDisplay destinationDisplay;
|
||||
|
||||
public String forBoarding;
|
||||
|
||||
public ServiceJourney serviceJourney;
|
||||
|
||||
public Quay quay;
|
||||
|
||||
public String aimedDepartureTime;
|
||||
|
||||
public String expectedArrivalTime;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.estimated;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link JourneyPattern} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class JourneyPattern {
|
||||
public Line line;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.estimated;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Line} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class Line {
|
||||
public String name;
|
||||
|
||||
public String transportMode;
|
||||
|
||||
public String publicCode;
|
||||
|
||||
public String id;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.estimated;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Quay} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class Quay {
|
||||
public String publicCode;
|
||||
|
||||
public String id;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.estimated;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link ServiceJourney} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class ServiceJourney {
|
||||
public JourneyPattern journeyPattern;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.enturno.internal.model.simplified;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link DisplayData} is a Plain Old Java Objects class to wrap only needed data after processing API call results.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class DisplayData {
|
||||
public String stopPlaceId;
|
||||
|
||||
public String stopName;
|
||||
|
||||
public String transportMode;
|
||||
|
||||
public String lineCode;
|
||||
|
||||
public String frontText;
|
||||
|
||||
public List<String> departures;
|
||||
|
||||
public List<String> estimatedFlags;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.enturno.internal.model.stopplace;
|
||||
|
||||
import org.openhab.binding.enturno.internal.model.estimated.EstimatedCalls;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link StopPlace} from JSON.
|
||||
*
|
||||
* @author Michal Kloc - Initial contribution
|
||||
*/
|
||||
public class StopPlace {
|
||||
public java.util.List<EstimatedCalls> estimatedCalls;
|
||||
|
||||
public String name;
|
||||
|
||||
public String id;
|
||||
|
||||
public String transportMode;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="enturno" 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>Entur Binding</name>
|
||||
<description>Real-time timetable binding for Norwegian public transport operators.</description>
|
||||
<author>Michal Kloc</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<!-- Config for EnturTimeTable Binding -->
|
||||
<config-description uri="thing-type:enturno:linestop">
|
||||
<parameter name="stopPlaceId" type="text" required="true">
|
||||
<label>Stop Code</label>
|
||||
<description>Stop code that can be find here https://en-tur.no (id in link when stop is chosen).</description>
|
||||
</parameter>
|
||||
<parameter name="lineCode" type="text" required="true">
|
||||
<label>Line Code</label>
|
||||
<description>Line code that can be find here https://en-tur.no (displayed when departures for stop are chosen).</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,3 @@
|
||||
# thing status
|
||||
offline.conf-error-missing-stopId = The 'stopId' parameter must be configured.
|
||||
offline.conf-error-missing-lineCode = The 'lineCode' parameter must be configured.
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="enturno"
|
||||
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 groups for EnturTimeTable Binding -->
|
||||
<channel-group-type id="stopPlace">
|
||||
<label>Stop Place</label>
|
||||
<description>This is a stop place.</description>
|
||||
<channels>
|
||||
<channel id="id" typeId="stop-id"/>
|
||||
<channel id="name" typeId="stop-name"/>
|
||||
<channel id="transportMode" typeId="stop-transport-mode"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="direction">
|
||||
<label>Line Direction</label>
|
||||
<description>This is the data for public transport line direction.</description>
|
||||
<channels>
|
||||
<channel id="lineCode" typeId="line-code"/>
|
||||
<channel id="frontDisplayText" typeId="front-display"/>
|
||||
<channel id="departure01" typeId="departure"/>
|
||||
<channel id="departure02" typeId="departure"/>
|
||||
<channel id="departure03" typeId="departure"/>
|
||||
<channel id="departure04" typeId="departure"/>
|
||||
<channel id="departure05" typeId="departure"/>
|
||||
<channel id="estimatedFlag01" typeId="is-real"/>
|
||||
<channel id="estimatedFlag02" typeId="is-real"/>
|
||||
<channel id="estimatedFlag03" typeId="is-real"/>
|
||||
<channel id="estimatedFlag04" typeId="is-real"/>
|
||||
<channel id="estimatedFlag05" typeId="is-real"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<!-- Channels for EnturTimeTable Binding -->
|
||||
<channel-type id="departure">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Departure Time</label>
|
||||
<description>Time of departure.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="line-code">
|
||||
<item-type>String</item-type>
|
||||
<label>Line Code</label>
|
||||
<description>Code (usually number) of the public transport line.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="is-real">
|
||||
<item-type>String</item-type>
|
||||
<label>Estimated Flag</label>
|
||||
<description>Whether departure time is calculated/estimated or as in printed timetable (true/false).</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="front-display">
|
||||
<item-type>String</item-type>
|
||||
<label>Front Display</label>
|
||||
<description>Front display usually shows direction of the line.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="stop-id">
|
||||
<item-type>String</item-type>
|
||||
<label>Stop Id</label>
|
||||
<description>Id of the stop place.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="stop-name">
|
||||
<item-type>String</item-type>
|
||||
<label>Stop Name</label>
|
||||
<description>Name of the stop place.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="stop-transport-mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Stop Transport Mode</label>
|
||||
<description>Bus/Tramway/Plane etc.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="enturno"
|
||||
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">
|
||||
|
||||
<!-- LineStop Type -->
|
||||
<thing-type id="linestop">
|
||||
<label>Entur Timetable</label>
|
||||
<description>Provides real-time (estimated) departure timetable for chosen public transport line and stop in Norway.
|
||||
Data provided by Entur.no API.</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="stopPlace" typeId="stopPlace"/>
|
||||
<channel-group id="Direction01" typeId="direction">
|
||||
<label>Direction 1</label>
|
||||
<description>This is the real-time table for direction nr 1.</description>
|
||||
</channel-group>
|
||||
<channel-group id="Direction02" typeId="direction">
|
||||
<label>Direction 2</label>
|
||||
<description>This is the real-time table for direction nr 2.</description>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<config-description-ref uri="thing-type:enturno:linestop"/>
|
||||
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
stopPlace(id: "{stopPlaceId}") {
|
||||
id
|
||||
name
|
||||
transportMode
|
||||
estimatedCalls(startTime:"{startDateTime}" timeRange: 86400, numberOfDepartures: 400) {
|
||||
realtime
|
||||
aimedArrivalTime
|
||||
aimedDepartureTime
|
||||
expectedArrivalTime
|
||||
expectedDepartureTime
|
||||
date
|
||||
forBoarding
|
||||
forAlighting
|
||||
destinationDisplay {
|
||||
frontText
|
||||
}
|
||||
quay {
|
||||
id
|
||||
publicCode
|
||||
}
|
||||
serviceJourney {
|
||||
journeyPattern {
|
||||
line {
|
||||
id
|
||||
name
|
||||
transportMode
|
||||
publicCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user