Use XMLTV with openHAB

xmltv
Tags: #<Tag:0x00007f51dc4fe068>

( ) #1

Maybe theres someone else, who is interested in working with EPG-informations in his or her openHAB environment.

This soloution is based on my wifes wish, having a simple ad-free way to see the current and next-running tv-show on all the commonly used channels in our country (and switching on the TV with the current channel running / or setting a timer for recording shows in the background / etc.).

This is just a first simple method to implement the most relevant infos into openHAB with the help of xmltv (http://wiki.xmltv.org/index.php/Main_Page) which serves as a base for e.g. a kodi-/tv-binding implementation (which is not a part of this implementation, yet).

But first things first - a word of caution:

  1. I´m not fully aware of the current legal status for grabbing channel- and show-informations from multiple web-sources (this is what a xmltv-grabber do) - so please consider checking your countries law, before grabbing data with xmltv.
  2. I´m not a developer, nor a skilled scripter (is there even a difference?! - whatever) - so please use any of the provided infos/scrips with caution and feel free to review anything - I´m willed to learn and making things better in the future.
  3. I´m using openHABian v1.4.1 on a Rpi3b+ for myself and the shown install-script and OH-rule may not work with a different directory-structure than the default (’/etc/openhab2/’) - but it should be realy easy to rewrite the script to your own needs.

So - what can this one do for you?

  • Showing Title and Subtitle for the currently running and next tv-show for all your selected channels
  • Start / Stoptime for currently running and next tv-show
  • There are a lot more informations available (like show description, cast-infos, channel-logos etc.) - but depending on the used xmltv-source, these informations may be incomplete - so I skipped them in this first version.


(EPG.sitemap - channel overview)


(EPG.sitemap - current show details)


(EPG.sitemap - next show details)

Installation steps

  1. Install & configure xmltv
    1.1. Automatic: Using my rudimentary bash install-script from here
    1.2. Manual: Follow these steps:
# Update system and install XMLTV
sudo apt-get update
sudo apt-get install xmltv

# Get 'epg_parser.py' from github - to extract values from the xml-files
sudo -u openhab wget https://raw.githubusercontent.com/sparetimetherapist/xlmtv_for_openhab/master/epg_parser.py -O /etc/openhab2/scripts/epg_parser.py

# Creating the needed directories
sudo -u openhab mkdir -p /etc/openhab2/html/epg/{data/tmp,conf}

# Configuring xmltv-grabber (this one is for EU channels)
sudo -u openhab /usr/bin/tv_grab_eu_egon --configure --config-file /etc/openhab2/html/epg/conf/epg_eu.conf

# Only execute the following if your timezone is not UTC (your local timezone is CET in this example)
sudo sed -i -e 's/UTC/CET/g' /usr/bin/tv_grep

# Now edit your xmltv-settings, using your favourite editor (exchange '!' with '=' to add a channel)
sudo -u openhab nano /etc/openhab2/html/epg/conf/epg_eu.conf
  1. Install EXEC-Binding and MAP / JS Transformation in openHAB
    2.1. epg_duration.js

  2. Create stuff in OH
    3.1. Reffer XMLTV-channelIDs to OH by creating a epg.map in the following syntax (depending on the channels you choose in the ‘epg_eu.conf’)

NULL=none
-=none
1=hd.daserste.de
2=hd.zdf.de

3.2. Create EPG.items (example for 2 channels / Create a new block for each channel you want to add)

Group       gTVChannel
Group       gTVStopTime

Number      EPG_Update                          "EPG Status [%s]"

///////////////////////// Channel 1 /////////////////////////////
String      TV_Channel_1_Name                   "Sender [%s]"                                                           (gTVChannel)
String      TV_Channel_1_CurrentShow            "Aktuell läuft [%s]"                                <live>
String      TV_Channel_1_NextShow               "Danach läuft [%s]"
DateTime    TV_Channel_1_CurrentShowStartTime   "Startzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"
DateTime    TV_Channel_1_NextShowStartTime      "Startzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"
DateTime    TV_Channel_1_CurrentShowStopTime    "Stopzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"                        (gTVStopTime)
DateTime    TV_Channel_1_NextShowStopTime       "Stopzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"
String      TV_Channel_1_NextShowStartStop      "Start / Ende [%s Uhr]"
String      TV_Channel_1_CurrentShowDuration    "Verbleibende Zeit [JS(epg_duration.js):%s]"
/////////////////////////////////////////////////////////////////

///////////////////////// Channel 2 /////////////////////////////
String      TV_Channel_2_Name                   "Sender [%s]"                                                           (gTVChannel)
String      TV_Channel_2_CurrentShow            "Aktuell läuft [%s]"                                <live>
String      TV_Channel_2_NextShow               "Danach läuft [%s]"
DateTime    TV_Channel_2_CurrentShowStartTime   "Startzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"
DateTime    TV_Channel_2_NextShowStartTime      "Startzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"   
DateTime    TV_Channel_2_CurrentShowStopTime    "Stopzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"                        (gTVStopTime)
DateTime    TV_Channel_2_NextShowStopTime       "Stopzeit [%1$td.%1$tm.%1$tY - %1$tH:%1$tM Uhr]"
String      TV_Channel_2_CurrentShowStartStop   "Start / Ende [%s Uhr]"
String      TV_Channel_2_NextShowStartStop      "Start / Ende [%s Uhr]"
String      TV_Channel_2_CurrentShowDuration    "Verbleibende Zeit [JS(epg_duration.js):%s]"
/////////////////////////////////////////////////////////////////

3.3. Create your OH rule-file: EPG.rule (works with as many channels as you want)

import java.io.File // You need to import this one for file-checking

// #############################################################
//                      Global EPG Settings
// #############################################################
//
// ----------------------- PREREQUISITES -----------------------
// 'Exec' Binding
// 'MAP' Transformation (including 'epg.map')
// 'xmltv' installed ('sudo apt-get install xmltv')
// 'epg_parser.py' in OH script-directory
// 
// 'JS' Transformation (for easier duration-calculation) [OPTIONAL]
// -------------------------------------------------------------
//
val xml_grabber = "tv_grab_eu_egon" // There may be a need to change the used grabber, depending on your region (this one is for EU channels)
val xml_path = "/etc/openhab2/html/epg/"
val script_path = "/etc/openhab2/scripts/"
//
// #############################################################

// -------------------------------------------------------------> START
//
//                      EPG Rule #1
//
// This rule crawls all the public available EPG-Sources based
// on the selection in your xmltv-config.
//
// This one requires internet-connection to execute!
//
// -------------------------------------------------------------
rule "EPG - Update 2-day forecast XMLTV-file"
when
    System started or // Execute on system startup...
    Time cron "0 3 0 * * ?" or // ... every night at 3 o'clock...
    Item EPG_Update received update 0 // ... and if another rule sends update '0' to 'EPG_Update'.
then
    // Define variables
    val epgConfig = new File(xml_path + "conf/epg_eu.conf")
    val epgSource = new File(xml_path + "data/epgsource.xml")

    // Abort if xmltv-config is missing
    if (epgConfig.isFile() == false || epgConfig.canRead() == false) {
        logError("EPG","EPG Error: Update/Initialization failed ('epg_eu.conf' is missing or can´t be accessed)")
        return
    }

    // Check if epgsource.xml is available...
    if (epgSource.isFile() && epgSource.canRead()) {
        val newdate = new DateTime(now().minusHours(12))
        val filedate = new DateTime(epgSource.lastModified())

        // Refresh epgsource.xml if it´s lastModified date is older>12h
        if(filedate.isBefore(newdate)) {
            logInfo("EPG","EPG: 'epgsource.xml' is available, but older than 12 hours - Starting update... ")
            executeCommandLine("sudo /usr/bin/" + xml_grabber + " --config-file " + xml_path + "conf/epg_eu.conf --days 2 --quiet --output " + xml_path + "data/epgsource.xml",5000)
            sendCommand(EPG_Update, 1) // continue with rule step #2
            return
        } else { return }
    } else {
        // Execute if epgsource.xml can´t be found or accessed.
        logInfo("EPG","EPG: 'epgsource.xml ' isn´t available or can´t be accessed - Fetching EPG-data...")
        executeCommandLine("sudo /usr/bin/" + xml_grabber + " --config-file " + xml_path + "conf/epg_eu.conf --days 2 --quiet --output " + xml_path + "data/epgsource.xml",5000)
        sendCommand(EPG_Update, 1) // continue with rule step #2
    }
end // -------------------------------------------------------------> END

// -------------------------------------------------------------> START
//
//                          EPG Rule #2
//
// This one minimizes the 'epgsource.xml' hourly, by creating
// another file for all shows running until NOW.
// 
// -------------------------------------------------------------
rule "EPG - Minimize XMLTV-file every hour"
when
    Time cron "0 0 * * * ?" or // Execute every hour...
    Item EPG_Update received update 1 // ... and if rule #1 sends a trigger
then
    // Check for 'epgsource.xml'
    val epgSource = new File(xml_path + "data/epgsource.xml") 
    if(epgSource.isFile() && epgSource.canRead()) { 

        // Extracts all shows running until NOW, depending on your local time
        executeCommandLine("sudo /usr/bin/tv_grep --on-after now --output " + xml_path + "data/epgsource_bynow.xml " + xml_path + "data/epgsource.xml",5000)
        sendCommand(EPG_Update, 2) // continue with rule #3 
        logInfo("EPG","EPG: 'epgsource.xml' successfully minimized.")
    } else {
        sendCommand(EPG_Update, 0) // if 'epgsource' wasn´t found - go back to rule #1...
        return
    }
end // -------------------------------------------------------------> END

// -------------------------------------------------------------> START
//
//                          EPG Rule #3
//
// Extract the current and next tv-shows for all selected
// channels from 'epgsource_bynow.xml'.
//
// -------------------------------------------------------------
rule "EPG - Get current and next tv-show from minimized XMLTV-file"
when
    Item EPG_Update received update 2 // Execute on update '2'
then
    // Check for 'epgsource_bynow.xml'
    val epgFiltered = new File(xml_path + "data/epgsource_bynow.xml")
    if(epgFiltered.isFile() && epgFiltered.canRead()) {

        // Split minimized xmltv-file into one for each channel
        executeCommandLine("sudo /usr/bin/tv_split --output " + xml_path + "data/%channel_bynow.xml " + xml_path + "data/epgsource_bynow.xml",5000) 

        gTVChannel.members.filter[ i | i.state != NULL ].forEach[ i |
            // Extract and transform channelID from item
            val chan = i.name.split("_").get(2).toString
            val channelId = transform("MAP", "epg.map", chan)

            // Query for current- and next-show infos
            val stop = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_bynow.xml -c get_stopextra",5000)
            executeCommandLine("sudo /usr/bin/tv_grep --on-after now --on-before now --output " + xml_path + "data/" + channelId + "_now.xml " + xml_path + "data/" + channelId + "_bynow.xml",5000)
            executeCommandLine("sudo /usr/bin/tv_grep --on-after " + stop + " --on-before " + stop + " --output " + xml_path + "data/" + channelId + "_next.xml " + xml_path + "data/" + channelId + "_bynow.xml",5000)
        ]

        // Continue to rule #4
        sendCommand(EPG_Update, 3) 
        return

    } else {
        logError("EPG", "EPG Error: Update failed ('epgsource_bynow.xml' is missing or can´t be accessed)" )
        sendCommand(EPG_Update, 1) // return to rule #2
        return
    }
end // -------------------------------------------------------------> END

// -------------------------------------------------------------> START
// 
//                          EPG Rule #4
//
// Extract all values from the *.xml-files and send them to 
// the corresponding openHAB-items.
//
// -------------------------------------------------------------
rule "EPG - Send updated infos to openHAB-items"
when
    Item EPG_Update received update 3 // Execute on update #3
then
    gTVChannel.members.forEach[ i |
        val room = i.name.split("_").get(0).toString
        val type = i.name.split("_").get(1).toString
        val chan = i.name.split("_").get(2).toString
        
        // Set variable item-names & transform values
        val currentShowTitleItem = room + "_" + type + "_" + chan + "_CurrentShow"
        val nextShowTitleItem = room + "_" + type + "_" + chan + "_NextShow"
        val currentShowStartTimeItem = room + "_" + type + "_" + chan + "_CurrentShowStartTime"
        val nextShowStartTimeItem = room + "_" + type + "_" + chan + "_NextShowStartTime"
        val currentShowStopTimeItem = room + "_" + type + "_" + chan + "_CurrentShowStopTime"
        val nextShowStopTimeItem = room + "_" + type + "_" + chan + "_NextShowStopTime"
        // val currentShowStartStopItem = room + "_" + type + "_" + chan + "_CurrentShowStartStop"
        val nextShowStartStopItem = room + "_" + type + "_" + chan + "_NextShowStartStop"
        // val logoURLItem = room + "_" + type + "_" + chan + "_LogoURL"
        val channelId = transform("MAP", "epg.map", chan)

        // Execute python-script
        val channelName = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_now.xml -c get_channelname",5000)
        val currentShowTitle = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_now.xml -c get_title",5000)
        val nextShowTitle = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_next.xml -c get_title",5000)
        val currentShowStartTime = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_now.xml -c get_starttime",5000)
        val nextShowStartTime = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_next.xml -c get_starttime",5000)
        val currentShowStopTime = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_now.xml -c get_stoptime",5000)
        val nextShowStopTime = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_next.xml -c get_stoptime",5000)
        // val currentShowStartStop = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_now.xml -c get_startstop",5000)
        val nextShowStartStop = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_next.xml -c get_startstop",5000)
        // val logoURL = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/" + channelId + "_now.xml -c get_logourl",5000)

        // Sending stuff to items
        sendCommand(i.name, channelName)
        sendCommand(currentShowTitleItem, currentShowTitle)
        sendCommand(nextShowTitleItem, nextShowTitle)
        if (currentShowStartTime != "" || currentShowStartTime != NULL) { sendCommand(currentShowStartTimeItem, currentShowStartTime.toString) }
        sendCommand(nextShowStartTimeItem, nextShowStartTime.toString)
        if (currentShowStopTime.toString != "" || currentShowStopTime.toString != NULL) { sendCommand(currentShowStopTimeItem, currentShowStopTime.toString) }
        sendCommand(nextShowStopTimeItem, nextShowStopTime.toString)
        // sendCommand(currentShowStartStopItem, currentShowStartStop.toString)
        sendCommand(nextShowStartStopItem, nextShowStartStop.toString)
        // sendCommand(logoURLItem, logoURL)
    ]

    // Calculate remaining show time for current runnning show
    gTVStopTime.members.forEach[ i |
        val currentShowDuration = i.name.split("_").get(0).toString+"_"+i.name.split("_").get(1).toString+"_"+i.name.split("_").get(2).toString+"_CurrentShowDuration"
        val oldDate = new DateTime((i.state as DateTimeType).calendar.timeInMillis).millis
        val newDate = new DateTime(now()).millis
        val duration = (((oldDate-newDate) / 1000) / 60)
        sendCommand(currentShowDuration, duration.toString)
    ]

    sendCommand(EPG_Update, 4) // Sending successfull value to update-item
    logInfo("EPG","EPG: openHAB-items succesfully updated! \u2713")
end // -------------------------------------------------------------> END

// -------------------------------------------------------------> START
//
//                          EPG Rule #5  
//
// This rule is very important to reduce the system calls to a
// minimum - it checks, if the stop-time of any of the current 
// running tv-shows is reached.
//
// -------------------------------------------------------------
rule "EPG - Check if an EPG update is needed"
when
    Time cron "0 0/1 * * * ?" // Execute every minute...
then
    // Check for 'epgsource_bynow.xml'
    val epgByNow = new File(xml_path + "data/epgsource_bynow.xml")
    if(epgByNow.isFile() && epgByNow.canRead()) { 

        // Calculate remaining show time for current runnning show
        gTVStopTime.members.forEach[ i |
            val currentShowDuration = i.name.split("_").get(0).toString+"_"+i.name.split("_").get(1).toString+"_"+i.name.split("_").get(2).toString+"_CurrentShowDuration"
            val oldDate = new DateTime((i.state as DateTimeType).calendar.timeInMillis).millis
            val newDate = new DateTime(now()).millis
            val duration = (((oldDate-newDate) / 1000) / 60)
            sendCommand(currentShowDuration, duration.toString)
        ]

        // Get timetsamp of the show with the earliest stoptime
        val stopTime = executeCommandLine("sudo python " + script_path + "epg_parser.py -t " + xml_path + "data/epgsource_bynow.xml -c get_stopextra",5000) 
        val DateTimeType timestamp = DateTimeType.valueOf(stopTime) // Convert human readable time stamp to DateTimeType

        // Compare current time with earliest stopDate of the current running shows
        if (now.isAfter(new DateTime(timestamp.zonedDateTime.toInstant.toEpochMilli)) ) { 
            executeCommandLine("sudo /usr/bin/tv_grep --on-after now --output " + xml_path + "data/epgsource_bynow.xml " + xml_path + "data/epgsource.xml",5000) // Update 'epgsource_bynow.xml'
            sendCommand(EPG_Update, 2) // execute rule #2
            logInfo("EPG", "EPG: A TV-show has ended. Starting update...")
        } else { return }
    } else {
        logError("EPG", "EPG Error: Update failed ('epgsource_bynow.xml' is missing or can´t be accessed)" )
        sendCommand(EPG_Update, 1) // return to rule #2
        return
    }
end // -------------------------------------------------------------> END

3.4. And thats what your EPG.sitemap could look like:

sitemap epg label="EPG"
{
    Frame label="" {
        Text item=TV_Channel_1_CurrentShow label="Das Erste [%s]" icon="tv_ard" {
            Frame item=TV_Channel_1_Name label="" {
                Text item=TV_Channel_1_CurrentShow icon="tv_ard"
                Text item=TV_Channel_1_CurrentShowDuration icon="time"
            }
        }
        Text item=TV_Channel_1_NextShow icon="next" {
            Frame item=TV_Channel_1_Name label="" {
                Text item=TV_Channel_1_NextShow label="Das Erste" icon="tv_ard"
                Text item=TV_Channel_1_NextShowStartStop
            }
        }
    }
    
    Frame label="" {
        Text item=TV_Channel_2_CurrentShow label="ZDF [%s]" icon="tv_zdf" {
            Frame item=TV_Channel_2_Name label="" {
                Text item=TV_Channel_2_CurrentShow icon="tv_zdf"
                Text item=TV_Channel_2_CurrentShowDuration icon="time"
            }
        }
        Text item=TV_Channel_2_NextShow icon="next" {
            Frame item=TV_Channel_2_Name label="" {
                Text item=TV_Channel_2_NextShow label="Das Erste" icon="tv_ard"
                Text item=TV_Channel_2_NextShowStartStop
            }
        }
    }
}

The rule should trigger an initial update automatically, after you created the above files.

If you find any errors or have improvements for anything, please tell me!


(Gaël L'hopital) #2

FYI a binding is on PR for the same :slight_smile:


( ) #3

Ahh, good to know! :slight_smile: Do you have any links with more infos on that - would love to know more. Thank you!


(Wouter Born) #4

That’s a nice EPG in Basic UI @Simson! Now if only there was something good on TV. :wink:

Here’s a link to the binding PR:

You can also test it with this org.openhab.binding.xmltv-2.4.0-SNAPSHOT.jar build by Jenkins.


( ) #5

Thanks for the link. Gave it a try and got some errors while trying to add a channel - but it´s still in developement, so maybe I just have to wait a bit more. :slight_smile:

For completeness this was my used *.things-file:

xmltv:XmlTVFile:bridge      [filePath="/etc/openhab2/html/epg/data/epgsource.xml", refresh=24]
xmltv:Channel:bridge:ARD    [channelId="hd.daserste.de", offset=0, refresh=60]

and the error in my log looks like…

2018-12-21 00:31:12.335 [WARN ] [mmon.WrappedScheduledExecutorService] - Scheduled runnable ended with an exception: 
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
	at java.util.ArrayList.rangeCheck(ArrayList.java:657) ~[?:?]
	at java.util.ArrayList.get(ArrayList.java:433) ~[?:?]
	at org.openhab.binding.xmltv.internal.handler.ChannelHandler.updateChannel(ChannelHandler.java:151) ~[?:?]
	at org.openhab.binding.xmltv.internal.handler.ChannelHandler.lambda$1(ChannelHandler.java:92) ~[?:?]
	at java.util.ArrayList.forEach(ArrayList.java:1257) ~[?:?]
	at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080) ~[?:?]
	at org.openhab.binding.xmltv.internal.handler.ChannelHandler.lambda$0(ChannelHandler.java:92) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:?]
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
	at java.lang.Thread.run(Thread.java:748) [?:?]

(JustAProgrammer) #6

Hey, really nice setup, I love it!
But is there an easier way to configure the needed channels?


(Wouter Born) #7

Thanks for helping with testing! I’ve added a review comment for this at that line number.


( ) #8

Thanks for your kind words!
With easier configuration, you mean the configuration of xmltv? Or the OH-part of this setup (MAP, rules, items etc.)?

I think, there won´t be a much easier way to configure the channels until the mentioned binding is ready - even then, you have to configure each channel as a separate thing with a bunch of items connected.

The *.MAP in my example handles the channelIDs similar to what the binding does with the ‘Channel’-things.


(JustAProgrammer) #9

you’re welcome! :slight_smile:

Yeah, I meant the xmlTV channels…

sudo -u openhab /usr/bin/tv_grab_eu_egon --configure --config-file /etc/openhab2/html/epg/conf/epg_eu.conf

It’s not that bit of a fun clicking through so many channels
Maybe they’re backupd in a file and can be edited …


( ) #10

Yeah, it isn´t. I did that once and have regretted it. Round about 1.000 channels only for the EU region… :worried:
While configuring the grabber, you could type in “none” in the selection of the channels and edit the file much easier afterwards with your favourite editor:
/etc/openhab2/html/epg/conf/epg_eu.conf

Just exchange the ‘!’ with an ‘=’ to add a channel to your selection. But you still have to go through all the ~1000 lines of channels…


(Kristof Rado) #11

how this binding will work if it is complete? You have to configure xmltv to run eg.: once per day and update that file which is given for OH as the source?


(Wouter Born) #12

I don’t use it myself but if I read the README it looks like you’d have to download the file yourself.

Would it make sense to replace filePath with a URL and so it can support both file and HTTP URLs @glhopital ?


(Gaël L'hopital) #13

Yes, currently you have to place the file yourself, or by shell script in the dedicated place. It will be read every day


(Gaël L'hopital) #14

Not sure because there are many distinct ways to grab / build the XML file depending on the country where one is. Plus some are available online a ZIP, so at this stage, I prefered let this out of the binding.


(JustAProgrammer) #15

while using the EPG.rules script I noticed running into a endless loop:
between the end of rule 1

    } else {
        // Ausführen falls epgsource.xml nicht auffind- oder bearbeitbar ist.
        logInfo("EPG","EPG: 'epgsource.xml ' ist nicht verfügbar oder bearbeitbar - holen von EPG-data...")
        executeCommandLine("sudo /usr/bin/" + xml_grabber + " --config-file " + xml_path + "conf/epg_eu.conf --days 2 --quiet --output " + xml_path + "data/epgsource.xml",5000)
        sendCommand(EPG_Update, 1) // continue with rule step #2
    }

and rule 2:

// -------------------------------------------------------------
rule "EPG - Minimiert XMLTV-Datei jede Stunde"
when
    Time cron "0 0 * * * ?" or // Ausführung in jeder Stunde...
    Item EPG_Update received update 1 // ... und falls Regel #1 einen Trigger sendet
then
    // Checkt verfügbarkeit von 'epgsource.xml'
    val epgSource = new File(xml_path + "data/epgsource.xml") 
    if(epgSource.isFile() && epgSource.canRead()) { 

        // Extrahiert alle Shows die jetzt laufen, hängt von der lokalen Zeit ab
        executeCommandLine("sudo /usr/bin/tv_grep --on-after now --output " + xml_path + "data/epgsource_bynow.xml " + xml_path + "data/epgsource.xml",5000)
        sendCommand(EPG_Update, 2) // weitermachen mit regel #3 
        logInfo("EPG","EPG: 'epgsource.xml' successfully minimized.")
    } else {
        sendCommand(EPG_Update, 0) // falls 'epgsource' nicht gefunden wurde - Zurück zu Regel #1...
        return
    }
end // -------------------------------------------------------------> END

epgsource.xml will never be created…
running the command manually gets me this output:


(every path is valid)
Looks like this command wants an input …

when editing

sudo nano /usr/bin/tv_grap_eu_egon

it’s actually completly empty, how can I get it to be filled with data?

Logfile while the Loop occurs:


( ) #16

Oh okay, thanks for the info with this speacial loop, when failing to create the epgsource.xml.

Theres a lot of garbage going on in this first version of my script - but i´m working on a much better (and faster) version of this right now (until the real binding gets released). which I´ll finish tommrrow, I hope.

But the error seems not related to the OH-rule… Did you install and configure xmltv already?

sudo apt-get install xmltv

The best way would be to wait until tommorrow, when I will update this post with a more detailed description and better version. :slight_smile:


(JustAProgrammer) #17

Cool, will rewrite it in Jython when I find time and finally be familiar with the JSR223 API! :slight_smile:

Yes of course, it’s the latest version.
I’ve even looked through your shell script and can’t find anything I didn’t do …

I’m for sure hyped to look into it :wink:


(JustAProgrammer) #18

any updates?

creating the epcsource.xml worked I’ve just had a silly syntax fail:

sudo /usr/bin/tv_grab_eu_egon --config-file /etc/openhab2/html/epg/conf/epg_eu.conf --days 2 --quiet --output /etc/openhab2/html/epg/data/epgsource.xml

thankfully did it!

But I’m running into the next loop:

2019-01-10 13:07:09.277 [ERROR] [g.eclipse.smarthome.model.script.EPG] - EPG Error: Update fehlgeschlagen ('epgsource_bynow.xml' ist nicht vorhanden oder kann nicht bearbeitet werden)

==> /var/log/openhab2/events.log <==

2019-01-10 13:07:09.280 [ome.event.ItemCommandEvent] - Item 'EPG_Update' received command 1

2019-01-10 13:07:09.287 [vent.ItemStateChangedEvent] - EPG_Update changed from 2 to 1

==> /var/log/openhab2/openhab.log <==

2019-01-10 13:07:09.346 [INFO ] [g.eclipse.smarthome.model.script.EPG] - EPG: 'epgsource.xml' successfully minimized.

==> /var/log/openhab2/events.log <==

2019-01-10 13:07:09.350 [ome.event.ItemCommandEvent] - Item 'EPG_Update' received command 2

2019-01-10 13:07:09.354 [vent.ItemStateChangedEvent] - EPG_Update changed from 1 to 2

==> /var/log/openhab2/openhab.log <==

2019-01-10 13:07:09.360 [ERROR] [g.eclipse.smarthome.model.script.EPG] - EPG Error: Update fehlgeschlagen ('epgsource_bynow.xml' ist nicht vorhanden oder kann nicht bearbeitet werden)

==> /var/log/openhab2/events.log <==

2019-01-10 13:07:09.366 [ome.event.ItemCommandEvent] - Item 'EPG_Update' received command 1

2019-01-10 13:07:09.373 [vent.ItemStateChangedEvent] - EPG_Update changed from 2 to 1

==> /var/log/openhab2/openhab.log <==

2019-01-10 13:07:09.433 [INFO ] [g.eclipse.smarthome.model.script.EPG] - EPG: 'epgsource.xml' successfully minimized.

I’m gonna look into that.
Edit:
Same thing:

// Extrahiert alle Shows die jetzt laufen, hängt von der lokalen Zeit ab
        executeCommandLine("sudo /usr/bin/tv_grep --on-after now --output " + xml_path + 
"data/epgsource_bynow.xml " + xml_path + "data/epgsource.xml",5000)

Didn’t get executed, and fails at this if statement (obviously lol)

if(epgFiltered.isFile() && epgFiltered.canRead())

after running


the rule works fine!
Thanks, hope I could helped others implement xmltv!


(Tobias) #19

Are there any plans to combine this with a triggered Switch that would allow me to switch off my Horizon box when it is not needed? Something similar to the CalDAV binding…?
Thanks!


(Geoff) #20

Hi All i am trying to get the xmltv Binding to work at the moment i have installed it in OpenHAB2.5 build #1545 and it configure up correctly creates the channel thing from the xml file but fails to capture any additional real data is there something else i need to do to get the data into the channels