
CHAPTER 7 ■ CONTROL HUBS
248
Figure 7-6. The photo frame can operate as a slide show on kiosk machines.
By clicking the main image, this app can work in the full browser window, making it suitable as an
interactive photo frame for those times when a machine is not being used as a control panel. You can
cycle through the images using hotspots on the left and right of the image, while the lower portion
returns you to non-full-screen mode. The Internet has a lot of available images to fit the frame, including
those for the culture vultures at http://www.most-famous-paintings.org.
Information
These applets provide information about the real world, which is also useful and valid when outside the
house. There is potential overlap from these and your lifestyle, but it’s a good enough distinction for
now!
Moonbeam is an applet that relies on MySQL to store a list of bookmarks, each with multiple tags. It
is similar to http://del.icio.us, except that all data is held on your own server. To prepare the
database, you can run the build/applets/moonbeam/createdb.sql script using your existing root account:
$ mysql -u your_username -h your_machine_name -p < createdb.sql
Then enter your password to build an empty database. You can populate it with sample links by
adding the same credentials to the config.php file in the same directory and running the following:
php init.php
You can then add this account information to the Moonbeam’s web configuration at
conf/moonbeam/config.php and use the applet as normal. If you want to create an alternate user to access
the Moonbeam database (which is recommended), then log into MySQL and enter the following:
CREATE USER 'moonbeam'@'localhost' IDENTIFIED BY 'some_pass';
GRANT SELECT on moonbeam.* TO 'moonbeam'@'localhost';

CHAPTER 7 ■ CONTROL HUBS
249
And amend the web configuration, as shown earlier.
The weather applet simply reads the precached forecasts (made earlier in the day by the Minerva
user’s crontab) stored in /var/log/minerva/cache/weather.txt and
/var/log/minerva/cache/weather_info.txt to look for matching strings that determine which icon will
be drawn on the page.
There is also a currency calculator, based on the http://xurrency.com web service you saw in
Chapter 6. Its inclusion is primarily educational.
Another applet that merely wraps an existing Bearskin command consists of live departure boards.
It calls $MINBASE/bin/ldbquery to determine the next trains from your predetermined stations. There is
no configuration here, since the ldbquery script accepts arguments designated as the source and
destination stations on your journey from hard-coded values in the applet.
And finally, the RSS news applet makes use of the news-read command to render the most recent
news stories into your browser. Each news feed is governed by the unique pairing of a site ID and
username, which presents a file stored in $MINBASE/etc/users/public/news/slashdot, for example, that
holds the site name and URL for the RSS feed:
Slashdot
http://rss.slashdot.org/Slashdot/slashdot
This news is downloaded on demand, either explicitly with news-get public slashdot or implicitly
when a story is read with news-read slashdot public text 0 headline. At this point, the RSS content is
downloaded and stored in a local cache where the various elements can be read. The system is smart
enough to not redownload content if it is fairly fresh and can render the output in text, HTML, or vocal-
friendly text. The latter case removes any markup. The WARP applet displays the elements, headline,
URL, and story, individually, using the news-read arguments shown earlier. The same approach can be
used on the command line, allowing the alarm clock to include a line such as the following to give you
the headlines in the morning:
$MINBASE/bin/say default `news-read slashdot public vox 0 headline`
Administration
These are all very simple applets to quickly review the status logs, processes, and server, without you
having to log in through SSH. You will need to have authority to use these tools, so give yourself
permission with the following:
minuser auth [myusername] system set rw
The typical applets available here report the following:
• Free disk space (the specific devices can be specified in
warp/conf/diskfree/diskfree.conf)
• User agent of the browser (for debugging mainly)
• Samba status
• Processor top

CHAPTER 7 ■ CONTROL HUBS
250
• UPS status
• Various log files
• Bluetooth scanner results
Creating Your Own Applets
To fully appreciate the development methodology of applets, it’s necessary to know a little about WARP.
WARP is a system built on WebFace that abstracts the basic elements of web design to ensure that the
control logic and presentation elements are strictly separated. This means that it’s not possible to add a
link in your page with the following:
<a href="process.php?bedroom_light=on">Switch Light On</a>
but instead you have to ask an applet manager to generate one for you:
$html = $appMan->getAppletLink($applet, "on", "bedroom_light", "Switch Light On");
You would then pick up the argument like this:
$prm = $appMan->queryParameter($applet, "bedroom_light");
This approach has several benefits. Naturally, it forces a separation between logic and display,
which encourages more structured code, and it means you can place the applet onto any page you like,
since the page itself isn’t mentioned. But more important, it allows for an easy upgrade path. WARP is
based on something akin to a RESTful approach. Because HTTP is a stateless protocol, there is no way of
remembering the user action from one page to the next. Some web sites do this by using lots of different
pages, where the page itself is an implicit reminder of the state. Some will create server-side objects that
remember the state and last for as long as your browser is looking at the page or until an arbitrary
timeout. WARP does this by recording the state as part of the URL. And with several applets appearing
on each page, each applet must therefore have its own part of the URL indicating its own state. A typical
URL might appear as follows:
http://my.minervahome.net/minerva/wmm.php?WRP001X1_user=0&WRP001X1_day=0&WRP002X3_dpage
=0&WRP002X3_fpage=0&WRP004X6_current=/&WRP004X6_dpage=0&WRP004X6_fpage=0&wintype
=main&content=WRP002X&max=WRP002X
If you dissect this carefully, you can see that each parameter fits the pattern of WRP, followed by a
three-digit applet code, an X separator and parameter index number, an underscore, and then a
name/value pair. There are also some parameters that describe WARP’s internal state in the form of
wintype, content, and max. Naturally, attempting to generate or parse this URL manually would be
foolhardy!

CHAPTER 7 ■ CONTROL HUBS
251
The WARP Directories
There are three directories of note inside minerva/warp:
applets: The code and assets for each of the applets, inside their own
subdirectory
conf: The configuration data for the earlier applets, inside an identically named
subdirectory
warplib: The base and operational classes for the applet and applet manager
The Components of WebFace
Each abstraction in WebFace covers one of the four areas in WARP code design. References to each can
be retrieved from the applet manager with functions and functionality as follows:
getAuth(): Authorization. This module will let you know whether the user has
logged in and been authenticated by the Apache server using the method
getUser. Since the Apache user ID is administered manually to match the
Minerva username, this can be used to present the TV guide and other user-
specific data on a web page. This module also connects to the minuser code,
through isUserValidFor, to provide fine-level control over the various applets.
This makes it possible for many people to see the currently playing CD or MP3
track but for only a privileged few to change it (warp/warplib/appauth.inc).
getCtrl(): Control. Generates anchors for web links, although I’ll cover this in
detail next.
getView(): Viewport. This is used to combine multiple blocks of individual data
into a single frame. The metaphor used here is pane, since they are combined
to form windows. The default functionality allows you to combine these into
horizontally or vertically, aligned windows of two, three, or four panes
(webface/webview.inc).
getDbug(): Debug. This is a utility submodule that allows individual errors,
warnings, and information lines to be logged. Once the HTML has been built,
the complete list can be written out using dumpAll. This is done since output
written to arbitrary parts of the web page can break the formatting badly and, in
the case of cookies, prevent the page from loading altogether
(webface/webdbug.inc).
The Basic Structure
Almost every applet begins the same way, with a directory inside warp/applets and a new applet class
taken from the template as follows:
<?php
require_once 'system/setup.conf';
require_once 'warp/warplib/applet.inc';

CHAPTER 7 ■ CONTROL HUBS
252
class Warp_TODO_Applet extends Warp_Applet
{
function Warp_TODO_Applet($caption = "TODO List")
{
parent::__construct($caption);
}
function getDirectory()
{
return "todo";
}
function init(&$appMan)
{
Warp_Applet::Init($appMan);
}
function renderPanel(&$appMan)
{
return "";
}
function renderWindow(&$appMan)
{
return "";
}
function renderInfo(&$app_man, $fast=false)
{
if ($fast) {
return "-";
}
return "Instructions...";
}
}
?>
You can easily see the blanks in which you fill the HTML code to form the panel, main window, and
help screen. These are the easy bits. The interesting code is in init and the hitherto unseen
getRefreshParams that control the parameters.
TODO: Controlling the Applet
With everything being controlled by parameters, you must take care to use them effectively. The best
way to do this is to think of the GET request as featuring two sets of parameters. The first set reflects the
refresh parameters and are those that you’d want to appear in the URL so that this state could be rebuilt
at a later date. The second set is the command parameters, indicating how that state is to change when
the page is reloaded.

