11

I'm using Raspberry Pi to create a non-interactive web kiosk - a specific webpage (measurements from a remote monitoring station) to be displayed on a screen in full screen mode, content refreshed frequently through AJAX.

Now there are quite a few solutions to making Raspberry into a kiosk, and I'm pretty sure I'll be able to do it just fine, but the kiosk should be quite maintenance-free. Especially in situation when power goes out, then comes back on, but somehow the router/modem/network infrastructure didn't quite come online.

In that situation Midori will come up with a page about "unable to connect" or something like that and it will be stuck like this until someone cycles the power again - since the webpage including its own autorefresh mechanism failed to load!

Now how can I force Midori to load the page when the network is available again, or something to similar effect (auto-refresh always every 15 minutes or so, or keep refreshing until the page loads or something like that.)?

If that option is unavailable for Midori, can you recommend some other solution?

  • I haven't got access to a Pi right now, and neither to Midori, but maybe Midori has dbus support? You could try running qdbus (from package libqt4-dbus) or some similar tool and look for Midori in there. Then you most probably can trigger a refresh of the page. – Arne Apr 12 '13 at 13:54
  • Even better: It seems Midori has something built in. Maybe you can try that and post an answer here. – Arne Apr 12 '13 at 14:07
  • Was my answer not useful? Would you like me to write a bash script instead of Python? If you need to use crontab, are there any errors which you can reply with? – xxmbabanexx Apr 13 '13 at 6:36
  • @xxmbabanexx: It was useful and I will surely accept it if no better ones appear. I have found an alternate solution which I will post once fully developed. I'm still hoping someone comes up with a solution that doesn't perform refresh if the page is working just fine but if that doesn't happen, your answer is perfectly acceptable and I will accept it. – SF. Apr 13 '13 at 9:25
  • @sf. Thanks for the additional info. Once I finish my math homework, I will edit my script to include network-connection checking. – xxmbabanexx Apr 13 '13 at 18:16
6

Assuming that you have Python on your system, there is an alternative to cron. I have created a quick Python 2.7.3 script which will reload Midori every 5 minutes.

#This program reloads midori every 5 minutes

#Redifine the variables below as you see fit

rest_time = 300 #Rest time is set to 300 seconds (5 minutes) 


import subprocess as sub #Imports terminal commands (needed for reload)
from time import sleep #Import sleep (allows an infinite loop to become dormant)

while True: #This is an infinite loop. This means that our script won't stop.
    sub.call(["midori", "-e", "Reload"]) #This forwards our command to the terminal
    sleep(rest_time) #Wait rest_time second(s), then start the loop again. 

If you need to change the amount of rest time, simply change the rest_time variable.

New Script

As you said that you needed the program to be "smart", I have edited it to make it so. When using this program, please don't open Midori manually; open it from the script. I has an odd habit of crashing due to the Speed Dialer if you do otherwise. It also runs on Python 2.7.3. If you don't want to do all of that copy and pasting, please visit my pastebin of the code.

"""
Midori Kiosk Reloader.
Created by xxmbabanexx

NOTE: This program opens Midori automatically. DO NOT OPEN IT MANUALLY, SIMPLY CLICK ON THIS PROGRAM.

KEYS

1 = Connection Complete. All is well.

0 = Connection Incomplete. Something is wrong.
"""


#Change these variables to your liking.

host = "www.google.com" #Put your desired host URL/IP between the quotes

port = 80 #Set to default port of 80. If your host uses something else, please change it.

recheck_time = 10 #The number of seconds the program will wait to ping the server. Change this at your leisure. 

page_to_open_to = "www.google.com" #This is the webpage the kiosk will open to. Put the url between the quotes.


#Excersise caution when changing these vars.

last = -1 #undefined state
up = -1 #Undefined state



"""
#---------------- Main code. Do NOT touch unless you KNOW what you are doing. ------------
"""
#Import modules

import subprocess as sub
from time import sleep
import socket
import threading

sub.Popen(["midori", "-a", page_to_open_to]) #open midori


#Check if internet is up
addr = (host, port) #the connection addr


while True:
    last = up #reset checking var
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #create socket
    try: #attempt to ping, change vars
        s.connect(addr)
        up = 1
        print "\n"
    except socket.error: #if error when pinging, change vars
        up = 0
        print "\n"

    print "LAST CHECK:", last
    print "CURRENT CHECK:", up
    if last == 0 and up == 1:
        print "Reloading Midori.\n"
        sub.call(["midori", "-e", "Reload"])
    s.close()


    sleep(recheck_time)
8

Just in case anyone comes by and is looking for an updated answer, Midori now has a command line option --inactivity-reset=SECONDS (or -i for short).

Coupled with the -a option, you can achieve a constantly restarting browser in kiosk mode every x seconds.

e.g.

midori -a http://www.google.com/ -i 120 -e Fullscreen

Will open http://www.google.com/ in a fullscreen window and refresh the page after 2 minutes of inactivity. (-e executes a command)

4

I decided to approach it from a different side, mostly browser-independent.

The browser is started in kiosk mode, pointing at a specific local document:

watchdog.html

<!DOCTYPE html>
<html>
    <head>
        <title>Monitoring</title>
        <script type="text/javascript">
        <!--
        var reload_url="http://example.org/watched.html";
        var to = 10000;  // Watchdog timeout: 10s.
        var wd;
        var ifr;
        function setup_watchdog()
        {
            ifr=document.getElementById("frame1");
            window.onmessage = function(e){
                if (e.data == 'tyrp') {
                    window.clearTimeout(wd);
                    wd = window.setTimeout(wdf,to);
                }
            };
            ifr.src = reload_url;
            wd = window.setTimeout(wdf,to);
        }

        function wdf()
        {
            ifr.src = reload_url;
            wd = window.setTimeout(wdf,to);
        }
        // -->
        </script>
    </head>
    <body onload="setup_watchdog()" style="margin: 0; overflow: hidden;">
        <iframe id="frame1" src="#" 
        style="position:absolute; left: 0px; width: 100%; top: 0px; height: 100%; margin:0; padding:0; border:0px none transparent;"></iframe>
    </body>
</html>

Now in this file, the timeout value is adjusted to contain two normal autorefreshes of the remote page plus some, and reload_url is set to its URL.

The remote page has a snippet that is executed every time its refresh is performed correctly:

try {
    window.top.postMessage('tyrp', '*');
} catch(e){}

If anything bad happens - the page fails to load, loads as 404 or error or its javascript stops for whatever reason, or some hijack redirect pushes us to a different page, if two consecutive refresh messages fail to arrive, the watchdog frame resets the URL to the original, which automatically performs reload.

Note, the try...catch is to prevent problems with older browsers which may not support postMessage. This won't be a problem with the kiosk since we control the environment and can always assure the right browser will be used. OTOH, on random client computers without the frame listening to the messages the postMessage operation is no-op as long as it doesn't cause script-aborting error, thus try..catch.

3

I use the xdotool to simulate an f5 keypress

pi@data-integrity-pi ~/log $ cat ~/bin/refresh_kiosk.sh
DISPLAY=:0 xdotool search --name ci-monitor windowactivate --sync key F5 >> ~/log/tmp.log 2>&1

and then in my crontab I run that script every minute

 */1 *   *   *   *    /home/pi/bin/refresh_kiosk.sh

Not the answer you're looking for? Browse other questions tagged or ask your own question.