added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.xmltv/.classpath
Normal file
32
bundles/org.openhab.binding.xmltv/.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="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" 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="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.binding.xmltv/.project
Normal file
23
bundles/org.openhab.binding.xmltv/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.xmltv</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
bundles/org.openhab.binding.xmltv/NOTICE
Normal file
13
bundles/org.openhab.binding.xmltv/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
|
||||
88
bundles/org.openhab.binding.xmltv/README.md
Normal file
88
bundles/org.openhab.binding.xmltv/README.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# XmlTV Binding
|
||||
|
||||
XMLTV is an XML based file format for describing TV listings.
|
||||
This format is often used by Home Theater software to produce their Electronic Program Guide (http://wiki.xmltv.org/index.php/Main_Page)
|
||||
|
||||
The norm allows to separate program display from its building.
|
||||
The building of the XMLTV file itself is taken in charge by so called "grabbers" (http://wiki.xmltv.org/index.php/HowtoUseGrabbers).
|
||||
|
||||
Some websites provides updated XMLTV files than can be directly downloaded.
|
||||
|
||||
Here is a sample for France : https://www.xmltv.fr/
|
||||
|
||||
This binding takes an XMLTV file as input and creates a thing for each channel contained in it.
|
||||
XmlTV channels are called Media Channels in this binding in order to avoid messing with openHAB Channels.
|
||||
|
||||
For each thing, you will be able to get information regarding the current program and the next to come.
|
||||
|
||||
## Supported Things
|
||||
|
||||
## Discovery
|
||||
|
||||
Once the XmlTV bridge to a file is created, you can add all known channels by searching new things.
|
||||
|
||||
## Binding Configuration
|
||||
|
||||
| Configuration Parameter | Required | Description | Default |
|
||||
|-------------------------|----------|-----------------------------------------------------|---------|
|
||||
| filePath | X | Full path (including filename) to an Xml TV file | |
|
||||
| refresh | X | XMLTV file reload interval in hours | 24h |
|
||||
| encoding | X | XMLTV file encoding | UTF8 |
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
| Configuration Parameter | Required | Description | Default |
|
||||
|-------------------------|----------|----------------------------------------------------------------|---------|
|
||||
| channelId | X | Id of the channel as presented in the XmlTV file | |
|
||||
| offset | X | Offset applied to program times (forward or backward (minutes) | 0 |
|
||||
| refresh | X | Refresh interval in seconds | 60 |
|
||||
|
||||
## Channels
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|----------------------|-------------------------------------|
|
||||
| iconUrl | String | Channel Icon URL |
|
||||
| icon | Image | Icon of the channel |
|
||||
|
||||
### Current program (currentprog) Channels Group
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|----------------------|---------------------------------------------|
|
||||
| progStart | DateTime | Program Start Time |
|
||||
| progEnd | DateTime | Program End Time |
|
||||
| progTitle | String | Program Title |
|
||||
| progCategory | String | Program Category |
|
||||
| progIconUrl | String | URL to an image of the program |
|
||||
| icon | Image | Icon of the program |
|
||||
| elapsedTime | Number:Time | Current time of currently playing program |
|
||||
| remainingTime | Number:Time | Time remaining until end of the program |
|
||||
| progress | Number:Dimensionless | Relative progression of the current program |
|
||||
|
||||
### Next program (nextprog) Channels Group
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|----------------------|---------------------------------------------|
|
||||
| progStart | DateTime | Program Start Time |
|
||||
| timeLeft | Number:Time | Time left before program start |
|
||||
| progEnd | DateTime | Program End Time |
|
||||
| progTitle | String | Program Title |
|
||||
| progCategory | String | Program Category |
|
||||
| progIconUrl | String | URL to an image of the program |
|
||||
| icon | Image | Icon of the program |
|
||||
|
||||
## Full Example
|
||||
|
||||
### xmltv.things
|
||||
|
||||
```
|
||||
Bridge xmltv:xmltvfile:france "XmlTV" @ "TV" [filePath="/etc/openhab2/scripts/tvguide.xml"]
|
||||
{
|
||||
Thing channel france2 "France 2" @ "TV" [channelId="C4.api.telerama.fr", offset=0, refresh=60]
|
||||
}
|
||||
```
|
||||
|
||||
### xmltv.items
|
||||
|
||||
```
|
||||
String france2_title "Titre" {channel="xmltv:channel:france:france2:currentprog#progTitle"}
|
||||
```
|
||||
17
bundles/org.openhab.binding.xmltv/pom.xml
Normal file
17
bundles/org.openhab.binding.xmltv/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.xmltv</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: XMLTV Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.xmltv-${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-xmltv" description="XMLTV Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature dependency="true">openhab.tp-jaxb</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.xmltv/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.xmltv.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link XmlTVBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class XmlTVBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "xmltv";
|
||||
|
||||
// List of all Bridge Type UIDs
|
||||
public static final ThingTypeUID XMLTV_FILE_BRIDGE_TYPE = new ThingTypeUID(BINDING_ID, "xmltvfile");
|
||||
public static final ThingTypeUID XMLTV_CHANNEL_THING_TYPE = new ThingTypeUID(BINDING_ID, "channel");
|
||||
|
||||
// Channel groups
|
||||
public static final String GROUP_CURRENT_PROGRAMME = "currentprog";
|
||||
public static final String GROUP_NEXT_PROGRAMME = "nextprog";
|
||||
public static final String GROUP_CHANNEL_PROPERTIES = "channelprops";
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_CHANNEL_URL = "iconUrl";
|
||||
public static final String CHANNEL_ICON = "icon";
|
||||
|
||||
public static final String CHANNEL_PROGRAMME_START = "progStart";
|
||||
public static final String CHANNEL_PROGRAMME_END = "progEnd";
|
||||
public static final String CHANNEL_PROGRAMME_TITLE = "progTitle";
|
||||
public static final String CHANNEL_PROGRAMME_CATEGORY = "progCategory";
|
||||
public static final String CHANNEL_PROGRAMME_ICON = "progIconUrl";
|
||||
|
||||
public static final String CHANNEL_PROGRAMME_ELAPSED = "elapsedTime";
|
||||
public static final String CHANNEL_PROGRAMME_REMAINING = "remainingTime";
|
||||
public static final String CHANNEL_PROGRAMME_PROGRESS = "progress";
|
||||
public static final String CHANNEL_PROGRAMME_TIMELEFT = "timeLeft";
|
||||
|
||||
// Supported Thing types
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(XMLTV_FILE_BRIDGE_TYPE, XMLTV_CHANNEL_THING_TYPE).collect(Collectors.toSet()));
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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.xmltv.internal;
|
||||
|
||||
import static org.openhab.binding.xmltv.internal.XmlTVBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.xmltv.internal.discovery.XmlTVDiscoveryService;
|
||||
import org.openhab.binding.xmltv.internal.handler.ChannelHandler;
|
||||
import org.openhab.binding.xmltv.internal.handler.XmlTVHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link XmlTVHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.xmltv", service = ThingHandlerFactory.class)
|
||||
public class XmlTVHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final Logger logger = LoggerFactory.getLogger(XmlTVHandlerFactory.class);
|
||||
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
|
||||
@Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
|
||||
if (XMLTV_FILE_BRIDGE_TYPE.equals(thingTypeUID)) {
|
||||
return super.createThing(thingTypeUID, configuration, thingUID, null);
|
||||
} else if (XMLTV_CHANNEL_THING_TYPE.equals(thingTypeUID)) {
|
||||
ThingUID newThingUID;
|
||||
if (bridgeUID != null && thingUID != null) {
|
||||
newThingUID = new ThingUID(thingTypeUID, bridgeUID, thingUID.getId());
|
||||
} else {
|
||||
newThingUID = thingUID;
|
||||
}
|
||||
return super.createThing(thingTypeUID, configuration, newThingUID, bridgeUID);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"The thing type " + thingTypeUID + " is not supported by the XmlTV binding.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (XMLTV_FILE_BRIDGE_TYPE.equals(thingTypeUID)) {
|
||||
try {
|
||||
XmlTVHandler bridgeHandler = new XmlTVHandler((Bridge) thing);
|
||||
registerDeviceDiscoveryService(bridgeHandler);
|
||||
return bridgeHandler;
|
||||
} catch (JAXBException e) {
|
||||
logger.error("Unable to create XmlTVHandler : {}", e.getMessage());
|
||||
}
|
||||
} else if (XMLTV_CHANNEL_THING_TYPE.equals(thingTypeUID)) {
|
||||
return new ChannelHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeHandler(ThingHandler thingHandler) {
|
||||
if (thingHandler instanceof XmlTVHandler) {
|
||||
Thing thing = thingHandler.getThing();
|
||||
unregisterDeviceDiscoveryService(thing);
|
||||
}
|
||||
super.removeHandler(thingHandler);
|
||||
}
|
||||
|
||||
private synchronized void registerDeviceDiscoveryService(XmlTVHandler bridgeHandler) {
|
||||
XmlTVDiscoveryService discoveryService = new XmlTVDiscoveryService(bridgeHandler);
|
||||
discoveryServiceRegs.put(bridgeHandler.getThing().getUID(),
|
||||
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
|
||||
}
|
||||
|
||||
private synchronized void unregisterDeviceDiscoveryService(Thing thing) {
|
||||
ServiceRegistration<?> serviceReg = discoveryServiceRegs.remove(thing.getUID());
|
||||
serviceReg.unregister();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.xmltv.internal.configuration;
|
||||
|
||||
/**
|
||||
* The {@link XmlChannelConfiguration} class contains fields mapping
|
||||
* Channel thing configuration parameters.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
public class XmlChannelConfiguration {
|
||||
public static final String CHANNEL_ID = "channelId";
|
||||
|
||||
public String channelId;
|
||||
public Integer offset;
|
||||
public Integer refresh;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.xmltv.internal.configuration;
|
||||
|
||||
/**
|
||||
* The {@link XmlTVConfiguration} class contains fields mapping TV bridge
|
||||
* configuration parameters.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
public class XmlTVConfiguration {
|
||||
public String filePath;
|
||||
public Integer refresh;
|
||||
public String encoding;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.xmltv.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.xmltv.internal.XmlTVBindingConstants.XMLTV_CHANNEL_THING_TYPE;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.xmltv.internal.XmlTVBindingConstants;
|
||||
import org.openhab.binding.xmltv.internal.configuration.XmlChannelConfiguration;
|
||||
import org.openhab.binding.xmltv.internal.handler.XmlTVHandler;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.Tv;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link XmlTVDiscoveryService} is responsible for discovering all channels
|
||||
* declared in the XmlTV file
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class XmlTVDiscoveryService extends AbstractDiscoveryService {
|
||||
private final Logger logger = LoggerFactory.getLogger(XmlTVDiscoveryService.class);
|
||||
|
||||
private static final int SEARCH_TIME = 10;
|
||||
|
||||
private XmlTVHandler bridgeHandler;
|
||||
|
||||
/**
|
||||
* Creates a XmlTVDiscoveryService with background discovery disabled.
|
||||
*/
|
||||
public XmlTVDiscoveryService(XmlTVHandler bridgeHandler) {
|
||||
super(XmlTVBindingConstants.SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
|
||||
this.bridgeHandler = bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Starting XmlTV discovery scan");
|
||||
if (bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
Tv tv = bridgeHandler.getXmlFile();
|
||||
if (tv != null) {
|
||||
tv.getMediaChannels().stream().forEach(channel -> {
|
||||
String channelId = channel.getId();
|
||||
String uid = channelId.replaceAll("[^A-Za-z0-9_]", "_");
|
||||
ThingUID thingUID = new ThingUID(XMLTV_CHANNEL_THING_TYPE, bridgeHandler.getThing().getUID(), uid);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withBridge(bridgeHandler.getThing().getUID())
|
||||
.withLabel(channel.getDisplayNames().get(0).getValue()).withRepresentationProperty(uid)
|
||||
.withProperty(XmlChannelConfiguration.CHANNEL_ID, channelId).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* 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.xmltv.internal.handler;
|
||||
|
||||
import static org.openhab.binding.xmltv.internal.XmlTVBindingConstants.*;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.xmltv.internal.configuration.XmlChannelConfiguration;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.Icon;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.MediaChannel;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.Programme;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.Tv;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.WithLangType;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.RawType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.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;
|
||||
|
||||
/**
|
||||
* The {@link ChannelHandler} is responsible for handling information
|
||||
* made available in regard of the channel and current program
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ChannelHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(ChannelHandler.class);
|
||||
|
||||
private @NonNullByDefault({}) ScheduledFuture<?> globalJob;
|
||||
private @Nullable MediaChannel mediaChannel;
|
||||
private @Nullable RawType mediaIcon = new RawType(new byte[0], RawType.DEFAULT_MIME_TYPE);
|
||||
|
||||
public final List<Programme> programmes = new ArrayList<>();
|
||||
|
||||
public ChannelHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
XmlChannelConfiguration config = getConfigAs(XmlChannelConfiguration.class);
|
||||
|
||||
logger.debug("Initializing Broadcast Channel handler for uid '{}'", getThing().getUID());
|
||||
|
||||
if (globalJob == null || globalJob.isCancelled()) {
|
||||
globalJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
if (programmes.size() < 2) {
|
||||
refreshProgramList();
|
||||
}
|
||||
if (programmes.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
|
||||
"No programmes to come in the current XML file for this channel");
|
||||
} else if (Instant.now().isAfter(programmes.get(0).getProgrammeStop())) {
|
||||
programmes.remove(0);
|
||||
}
|
||||
|
||||
getThing().getChannels().forEach(channel -> updateChannel(channel.getUID()));
|
||||
|
||||
}, 3, config.refresh, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshProgramList() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) {
|
||||
XmlTVHandler handler = (XmlTVHandler) bridge.getHandler();
|
||||
if (handler != null) {
|
||||
Tv tv = handler.getXmlFile();
|
||||
if (tv != null) {
|
||||
String channelId = (String) getConfig().get(XmlChannelConfiguration.CHANNEL_ID);
|
||||
|
||||
if (mediaChannel == null) {
|
||||
Optional<MediaChannel> channel = tv.getMediaChannels().stream()
|
||||
.filter(mediaChannel -> mediaChannel.getId().equals(channelId)).findFirst();
|
||||
if (channel.isPresent()) {
|
||||
mediaChannel = channel.get();
|
||||
mediaIcon = downloadIcon(mediaChannel.getIcons());
|
||||
}
|
||||
}
|
||||
|
||||
programmes.clear();
|
||||
tv.getProgrammes().stream().filter(
|
||||
p -> p.getChannel().equals(channelId) && p.getProgrammeStop().isAfter(Instant.now()))
|
||||
.forEach(p -> programmes.add(p));
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "No file available");
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (globalJob != null && !globalJob.isCancelled()) {
|
||||
globalJob.cancel(true);
|
||||
globalJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand {} for {}", command, channelUID);
|
||||
if (command == RefreshType.REFRESH) {
|
||||
refreshProgramList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last OpenUV data retrieved
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
*
|
||||
*/
|
||||
private void updateChannel(ChannelUID channelUID) {
|
||||
String[] uidElements = channelUID.getId().split("#");
|
||||
if (uidElements.length == 2) {
|
||||
int target = GROUP_NEXT_PROGRAMME.equals(uidElements[0]) ? 1 : 0;
|
||||
if (programmes.size() > target) {
|
||||
Programme programme = programmes.get(target);
|
||||
|
||||
switch (uidElements[1]) {
|
||||
case CHANNEL_ICON:
|
||||
State icon = null;
|
||||
if (GROUP_CHANNEL_PROPERTIES.equals(uidElements[0])) {
|
||||
icon = mediaIcon;
|
||||
} else {
|
||||
icon = downloadIcon(programme.getIcons());
|
||||
}
|
||||
updateState(channelUID, icon != null ? icon : UnDefType.UNDEF);
|
||||
break;
|
||||
case CHANNEL_CHANNEL_URL:
|
||||
updateState(channelUID,
|
||||
mediaChannel != null ? !mediaChannel.getIcons().isEmpty()
|
||||
? new StringType(mediaChannel.getIcons().get(0).getSrc())
|
||||
: UnDefType.UNDEF : UnDefType.UNDEF);
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_START:
|
||||
Instant is = programme.getProgrammeStart();
|
||||
ZonedDateTime zds = ZonedDateTime.ofInstant(is, ZoneId.systemDefault());
|
||||
updateState(channelUID, new DateTimeType(zds));
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_END:
|
||||
ZonedDateTime zde = ZonedDateTime.ofInstant(programme.getProgrammeStop(),
|
||||
ZoneId.systemDefault());
|
||||
updateState(channelUID, new DateTimeType(zde));
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_TITLE:
|
||||
List<WithLangType> titles = programme.getTitles();
|
||||
updateState(channelUID,
|
||||
!titles.isEmpty() ? new StringType(programme.getTitles().get(0).getValue())
|
||||
: UnDefType.UNDEF);
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_CATEGORY:
|
||||
List<WithLangType> categories = programme.getCategories();
|
||||
updateState(channelUID,
|
||||
!categories.isEmpty() ? new StringType(programme.getCategories().get(0).getValue())
|
||||
: UnDefType.UNDEF);
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_ICON:
|
||||
List<Icon> icons = programme.getIcons();
|
||||
updateState(channelUID,
|
||||
!icons.isEmpty() ? new StringType(icons.get(0).getSrc()) : UnDefType.UNDEF);
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_ELAPSED:
|
||||
updateState(channelUID, getDurationInSeconds(programme.getProgrammeStart(), Instant.now()));
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_REMAINING:
|
||||
updateState(channelUID, getDurationInSeconds(Instant.now(), programme.getProgrammeStop()));
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_TIMELEFT:
|
||||
updateState(channelUID, getDurationInSeconds(Instant.now(), programme.getProgrammeStart()));
|
||||
break;
|
||||
case CHANNEL_PROGRAMME_PROGRESS:
|
||||
Duration totalLength = Duration.between(programme.getProgrammeStart(),
|
||||
programme.getProgrammeStop());
|
||||
Duration elapsed1 = Duration.between(programme.getProgrammeStart(), Instant.now());
|
||||
|
||||
long secondsElapsed1 = elapsed1.toMillis() / 1000;
|
||||
long secondsLength = totalLength.toMillis() / 1000;
|
||||
|
||||
double progress = 100.0 * secondsElapsed1 / secondsLength;
|
||||
if (progress > 100 || progress < 0) {
|
||||
logger.debug("Outstanding process");
|
||||
}
|
||||
updateState(channelUID, new QuantityType<>(progress, SmartHomeUnits.PERCENT));
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
logger.warn("Not enough programs in XML file, think to refresh it");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private QuantityType<?> getDurationInSeconds(Instant from, Instant to) {
|
||||
Duration elapsed = Duration.between(from, to);
|
||||
long secondsElapsed = TimeUnit.MILLISECONDS.toSeconds(elapsed.toMillis());
|
||||
return new QuantityType<>(secondsElapsed, SmartHomeUnits.SECOND);
|
||||
}
|
||||
|
||||
private @Nullable RawType downloadIcon(List<Icon> icons) {
|
||||
if (!icons.isEmpty()) {
|
||||
String url = icons.get(0).getSrc();
|
||||
return HttpUtil.downloadImage(url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.xmltv.internal.handler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.xmltv.internal.configuration.XmlTVConfiguration;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.Programme;
|
||||
import org.openhab.binding.xmltv.internal.jaxb.Tv;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link XmlTVHandler} is responsible for handling XMLTV file and dispatch
|
||||
* information made available to according Media Channels
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class XmlTVHandler extends BaseBridgeHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(XmlTVHandler.class);
|
||||
private final XMLInputFactory xif = XMLInputFactory.newFactory();
|
||||
private final JAXBContext jc;
|
||||
|
||||
private @Nullable Tv currentXmlFile;
|
||||
private @NonNullByDefault({}) ScheduledFuture<?> reloadJob;
|
||||
|
||||
public XmlTVHandler(Bridge thing) throws JAXBException {
|
||||
super(thing);
|
||||
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
|
||||
jc = JAXBContext.newInstance(Tv.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
XmlTVConfiguration config = getConfigAs(XmlTVConfiguration.class);
|
||||
logger.debug("Initializing {} for input file '{}'", getClass(), config.filePath);
|
||||
|
||||
reloadJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
currentXmlFile = null;
|
||||
XMLStreamReader xsr = null;
|
||||
try {
|
||||
// This can take some seconds depending upon weight of the XmlTV source file
|
||||
xsr = xif.createXMLStreamReader(new FileInputStream(new File(config.filePath)), config.encoding);
|
||||
|
||||
try {
|
||||
Unmarshaller unmarshaller = jc.createUnmarshaller();
|
||||
Tv xmlFile = (Tv) unmarshaller.unmarshal(xsr);
|
||||
// Remove all finished programmes
|
||||
xmlFile.getProgrammes().removeIf(programme -> Instant.now().isAfter(programme.getProgrammeStop()));
|
||||
|
||||
if (!xmlFile.getProgrammes().isEmpty()) {
|
||||
// Sort programmes by starting instant
|
||||
Collections.sort(xmlFile.getProgrammes(), Comparator.comparing(Programme::getProgrammeStart));
|
||||
// Ready to deliver data to ChannelHandlers
|
||||
currentXmlFile = xmlFile;
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.DISABLED, "XMLTV file seems outdated");
|
||||
}
|
||||
xsr.close();
|
||||
} catch (JAXBException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, e.getMessage());
|
||||
}
|
||||
} catch (XMLStreamException | FileNotFoundException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (xsr != null) {
|
||||
xsr.close();
|
||||
}
|
||||
} catch (XMLStreamException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}, 0, config.refresh, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Running dispose");
|
||||
if (reloadJob != null && !reloadJob.isCancelled()) {
|
||||
reloadJob.cancel(true);
|
||||
reloadJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Tv getXmlFile() {
|
||||
return currentXmlFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.xmltv.internal.jaxb;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSchemaType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* Java class for an icon XML element
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType
|
||||
@XmlRootElement(name = "icon")
|
||||
public class Icon {
|
||||
|
||||
@XmlAttribute(required = true)
|
||||
protected String src;
|
||||
|
||||
@XmlAttribute
|
||||
@XmlSchemaType(name = "positiveInteger")
|
||||
protected BigInteger width;
|
||||
|
||||
@XmlAttribute
|
||||
@XmlSchemaType(name = "positiveInteger")
|
||||
protected BigInteger height;
|
||||
|
||||
public String getSrc() {
|
||||
return src;
|
||||
}
|
||||
|
||||
public BigInteger getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public BigInteger getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.xmltv.internal.jaxb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlSchemaType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Java class for an channel XML element
|
||||
* Renamed to MediaChannel in order to avoid confusion with ESH Channels
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType
|
||||
@NonNullByDefault
|
||||
public class MediaChannel {
|
||||
|
||||
@XmlElement(name = "display-name", required = true)
|
||||
protected List<WithLangType> displayNames = new ArrayList<>();
|
||||
|
||||
@XmlElement(name = "icon")
|
||||
protected List<Icon> icons = new ArrayList<>();
|
||||
|
||||
@XmlAttribute(required = true)
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlSchemaType(name = "token")
|
||||
protected String id = "";
|
||||
|
||||
public List<WithLangType> getDisplayNames() {
|
||||
return this.displayNames;
|
||||
}
|
||||
|
||||
public List<Icon> getIcons() {
|
||||
return this.icons;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.xmltv.internal.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* This object contains factory methods for each Java content
|
||||
* interface and Java element interface generated in the
|
||||
* org.openhab.binding.xmltv.internal.jaxb package.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@XmlRegistry
|
||||
@NonNullByDefault
|
||||
public class ObjectFactory {
|
||||
|
||||
/**
|
||||
* Create an instance of {@link Tv }
|
||||
*
|
||||
*/
|
||||
public Tv createTv() {
|
||||
return new Tv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link Programme }
|
||||
*
|
||||
*/
|
||||
public Programme createProgramme() {
|
||||
return new Programme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link MediaChannel }
|
||||
*
|
||||
*/
|
||||
public MediaChannel createChannel() {
|
||||
return new MediaChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link Icon }
|
||||
*
|
||||
*/
|
||||
public Icon createIcon() {
|
||||
return new Icon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link WithLangType }
|
||||
*
|
||||
*/
|
||||
public WithLangType createWithLangType() {
|
||||
return new WithLangType();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.xmltv.internal.jaxb;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Java class for a programme XML element
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType
|
||||
@NonNullByDefault
|
||||
public class Programme {
|
||||
private static final DateTimeFormatter XMLTV_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss Z");
|
||||
|
||||
@XmlElement(name = "title", required = true)
|
||||
protected List<WithLangType> titles = new ArrayList<>();
|
||||
|
||||
@XmlElement(name = "category")
|
||||
protected List<WithLangType> categories = new ArrayList<>();
|
||||
|
||||
@XmlElement(name = "icon")
|
||||
protected List<Icon> icons = new ArrayList<>();
|
||||
|
||||
@XmlAttribute(required = true)
|
||||
private String start = "";
|
||||
|
||||
@XmlAttribute
|
||||
private String stop = "";
|
||||
|
||||
@XmlAttribute(required = true)
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
protected String channel = "";
|
||||
|
||||
public List<WithLangType> getTitles() {
|
||||
return titles;
|
||||
}
|
||||
|
||||
public List<WithLangType> getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
public Instant getProgrammeStart() {
|
||||
long epoch = iso860DateToEpoch(start);
|
||||
return Instant.ofEpochMilli(epoch);
|
||||
}
|
||||
|
||||
public Instant getProgrammeStop() {
|
||||
long epoch = iso860DateToEpoch(stop);
|
||||
return Instant.ofEpochMilli(epoch);
|
||||
}
|
||||
|
||||
private long iso860DateToEpoch(String date) {
|
||||
long epoch = ZonedDateTime.parse(date, XMLTV_DATE_FORMAT).toInstant().toEpochMilli();
|
||||
return epoch;
|
||||
}
|
||||
|
||||
public List<Icon> getIcons() {
|
||||
return icons;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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.xmltv.internal.jaxb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Java class for a TV XML root element
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType
|
||||
@XmlRootElement(name = "tv")
|
||||
@NonNullByDefault
|
||||
public class Tv {
|
||||
@XmlElement(name = "channel")
|
||||
protected List<MediaChannel> channels = new ArrayList<>();
|
||||
|
||||
@XmlElement(name = "programme")
|
||||
protected List<Programme> programmes = new ArrayList<>();
|
||||
|
||||
public List<MediaChannel> getMediaChannels() {
|
||||
return this.channels;
|
||||
}
|
||||
|
||||
public List<Programme> getProgrammes() {
|
||||
return this.programmes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.xmltv.internal.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.XmlValue;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* Java class for an XML element value including a language attribute
|
||||
* information made available to according Media Channels
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "withLangType")
|
||||
public class WithLangType {
|
||||
|
||||
@XmlValue
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
protected String value;
|
||||
|
||||
@XmlAttribute
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
protected String lang;
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getLang() {
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@javax.xml.bind.annotation.XmlSchema(namespace = "", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
|
||||
package org.openhab.binding.xmltv.internal.jaxb;
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="xmltv" 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>XmlTV Binding</name>
|
||||
<description>This is the binding for reading and parsing XmlTV files</description>
|
||||
<author>Gaël L'hopital</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="xmltv"
|
||||
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="xmltvfile">
|
||||
<label>XmlTVFile</label>
|
||||
<description>This is the interface to a XmlTV file</description>
|
||||
|
||||
<config-description>
|
||||
<parameter name="filePath" type="text" required="true">
|
||||
<label>XmlTV File Path</label>
|
||||
<description>Path to an XmlTV file.</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" unit="h">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the XMLTV file reload interval in hours</description>
|
||||
<default>24</default>
|
||||
</parameter>
|
||||
<parameter name="encoding" type="text" required="true">
|
||||
<label>File encoding</label>
|
||||
<description>Specifies the XMLTV file encoding</description>
|
||||
<default>UTF8</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="channel">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="xmltvfile"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Channel</label>
|
||||
<description>This represent a channel on a given TV file</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="channelprops" typeId="channelprops"/>
|
||||
<channel-group id="currentprog" typeId="currentprog"/>
|
||||
<channel-group id="nextprog" typeId="nextprog"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
<parameter name="channelId" type="text" required="true">
|
||||
<label>Channel Id</label>
|
||||
<description>Id of the channel as presented in the XmlTV file.</description>
|
||||
</parameter>
|
||||
|
||||
<parameter name="offset" type="integer" min="-1440" max="1440" unit="min">
|
||||
<label>Offset</label>
|
||||
<description>Moves an event or datetime value forward or backward (in minutes)</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
|
||||
<parameter name="refresh" type="integer" unit="s">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in seconds</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
<channel-group-type id="channelprops">
|
||||
<label>Channel Properties</label>
|
||||
<description>Properties of the current channel</description>
|
||||
<channels>
|
||||
<channel id="iconUrl" typeId="iconUrl"/>
|
||||
<channel id="icon" typeId="icon"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="currentprog">
|
||||
<label>Current Program</label>
|
||||
<description>Program currently on air on this channel</description>
|
||||
<channels>
|
||||
<channel id="progStart" typeId="progStart"/>
|
||||
<channel id="progEnd" typeId="progEnd"/>
|
||||
<channel id="progTitle" typeId="progTitle"/>
|
||||
<channel id="progCategory" typeId="progCategory"/>
|
||||
<channel id="progIconUrl" typeId="progIconUrl"/>
|
||||
<channel id="icon" typeId="icon"/>
|
||||
<channel id="elapsedTime" typeId="elapsedTime"/>
|
||||
<channel id="remainingTime" typeId="remainingTime"/>
|
||||
<channel id="progress" typeId="progress"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="nextprog">
|
||||
<label>Next Program</label>
|
||||
<description>Program which will follow current program on this channel</description>
|
||||
<channels>
|
||||
<channel id="progStart" typeId="progStart"/>
|
||||
<channel id="timeLeft" typeId="timeLeft"/>
|
||||
<channel id="progEnd" typeId="progEnd"/>
|
||||
<channel id="progTitle" typeId="progTitle"/>
|
||||
<channel id="progCategory" typeId="progCategory"/>
|
||||
<channel id="progIconUrl" typeId="progIconUrl"/>
|
||||
<channel id="icon" typeId="icon"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="iconUrl" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Channel Icon URL</label>
|
||||
<description>Icon URL of the TV channel.</description>
|
||||
<state readOnly="true" pattern="%s"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="progIconUrl" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Program URL</label>
|
||||
<description>URL to an image of the program.</description>
|
||||
<state readOnly="true" pattern="%s"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="progTitle">
|
||||
<item-type>String</item-type>
|
||||
<label>Title</label>
|
||||
<description>Program Title.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="progCategory">
|
||||
<item-type>String</item-type>
|
||||
<label>Category</label>
|
||||
<description>Program Category.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="progStart">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Start Time</label>
|
||||
<description>Program Start Time</description>
|
||||
<state readOnly="true" pattern="%1$tF %1$tR"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="progEnd">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>End Time</label>
|
||||
<description>Program End Time</description>
|
||||
<state readOnly="true" pattern="%1$tF %1$tR"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="elapsedTime">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Current Time</label>
|
||||
<description>Current time of currently playing program.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="remainingTime" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Remaining Time</label>
|
||||
<description>Time remaining until end of the program.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="timeLeft" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Time Left</label>
|
||||
<description>Time left before program start</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="progress">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Progress</label>
|
||||
<description>Relative progression of the current program.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="icon">
|
||||
<item-type>Image</item-type>
|
||||
<label>Icon</label>
|
||||
<description>Icon of the channel / program.</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user