Making The Chumby function with a Shared Dictionary

The Chumby is a small inexpensive device capable of displaying a/v data. It is also an input device able to capture user interaction through a touch screen and a accelerometer. For these reasons, the Chumby can be called a “data appliance” or, in the terminology at Grouplab an Ambient Device. In this article, we show how to send messages and data to and from the Chumby and a Shared Dictionary.

THIS PAGE IS UNDER CONSTRUCTION!!!

Overview

The Chumby is a Linux based, wi-fi capable microcomputer. By default, it only runs small widgets, which are small Flash programs and movies. These movies are arranged into “channels”. Channels are collections of movies set up so that every x-number of seconds (by default 15) the device changes to display changes to the next script. This allows the chumby to, overtime, display a wide variety of small bits of data. These could be news headlines, webcam images, or sounds. After each script in the channel has been displayed, it begins again, at the start of the list.

The Linux core of the device has made it popular for hacking. Various people have written Chumby web servers, Chumby mp3 plays, and so forth. While the chumby is quite limited in terms of memory and processor power, the 2 USB ports on the back allows for additional memory or devices to be added to it.

Such properties potentially make the Chumby very attractive for prototyping domestic and ubiquitous computing applications. In a project that Kathryn and I worked on in 2006/2007 (see Location Aware Devices for the Home), we wanted a small, digital display device that could display flickr albums associated with a particular location. To this end, an excellent use of the Chumby would be to extend it to recognize and interact with phidgets and augment it with an RFID reader. By connecting the Chumby to a shared dictionary, it would have satisfied all our needs.

Extending the OS or functionality is outside of the scope of this small set of tutorials. We will use the device as it arrives out of the box. The goal is to show how it could be used in conjunction with Groups Lab’s Shared Dictionary, a component of the .Networking package. This is not always an easy task, and will require working in several programming languages. It will also require having unfettered access to a webserver.

For the purpose of this project, we will assume familiarity with C# and the .networking package. We will not assume any familiarity with Flash/Actionscript or PHP.

The difficulty comes from Flash. While current versions of Flash/Actionscript are less limited, the version of flash we will be able to use is extremely limited. The Chumby comes installed with Flash Lite 3.0, a simplified form of Flash 8.

In Flash 8, there are very limited methods available for inter-process communication. IPC is never easy, but here we are constrained solely to accessing webpages. That is, all data, including updates from the Shared Dictionary, that are transferred into or out of a Chumby, must be send through a webpage.

Shared Dictionary to Web

Language: C#

This stage of the project is basically a traditional shared dictionary project. We will create a small program that connects to a shared dictionary and updates a file on a webpage via ftp. The file that we will update can be an image, an mp3, an html file, or raw text.

A simple class for connecting to an FTP server and replacing a file called webserver.com/uploadedimage.jpeg :

    public class ftpUpdater
    {
        string ftpServer, ftpUserID, ftpPassword;
        public ftpUpdater(string newFtpServer, string newFtpUserID, string newFtpPassword)
        {
            ftpServer = newFtpServer;
            ftpUserID = newFtpUserID;
            ftpPassword = newFtpPassword;
        }

       // Takes an EasyImages  JPEG object and uploads it to the server
        public bool Upload(EasyImages.JPEG image)
        {
            byte[] imageBytes = image.GetByteArray();
            string uri = "ftp://" + ftpServer + "/" + "uploadedImage.jpg"; //Turn the server location into a full path
            FtpWebRequest reqFTP;
            reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));  // create a new instance of an FtpWebRequest
            reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword); //THe id/password for log in
            reqFTP.KeepAlive = false; //Terminate after file uploads
            reqFTP.Method = WebRequestMethods.Ftp.UploadFile;  //You want to upload a file
            reqFTP.UseBinary = true; //Transfer is binary
            reqFTP.ContentLength = imageBytes.Length; //How long is the file?
            try
            {
                Stream strm = reqFTP.GetRequestStream();
                strm.Write(imageBytes, 0, imageBytes.Length); //send a file of imageBytes.Length to the server
                strm.Close();
            }
            catch (Exception ex)
            {
                return false; //upload failed
            }
            return true; //upload successful!
        }
    }

Similarly, we update a text file

        public bool Upload(string newMessage)
        {
            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
            byte[] textBytes = encoding.GetBytes(newMessage);

            string uri = "ftp://" + ftpServer + "/" + "uploadedText.txt";
            FtpWebRequest reqFTP;

            reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
            reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
            reqFTP.KeepAlive = false;
            reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
            reqFTP.UseBinary = true;
            reqFTP.ContentLength = textBytes.Length;
            try
            {
                Stream strm = reqFTP.GetRequestStream();
                strm.Write(textBytes, 0, textBytes.Length);
                strm.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Upload Error");
                return false;
            }
            return true;
        }

As an example, here is a C# program ( Attach:SDFTPUploader.zip ) that takes webcam photos and puts them into a shared dictionary. When the shared dictionary is updated, it uploads the photo to the ftp site, and updates a textfile with an increasing number.

Usage:

1. Upon opening this program, the EasyImages webcam server will launch. Start the camera server. 2. In the main program window, press "Connect" and connect to the shared dictionary. 3. enter your ftp server and login data and press "log on"

Every 30 seconds the ftp server should be updated with a new image and a updated text file.

Web to Chumby

Language: Flash Lite 3.0

Having placed the value(s) on a website in part one, we now need to get them off and onto the Chumby.

Text

We'll start by creating a flash program that reads a website. It's available here ( Attach:text.fla ), but i've also written a tutorial. Anyway, open Flash CS3.

1. Begin by creating a new Flash 2.0 program

2. We now need to set up the document so that it can be displayed on a chumby

The dimensions should be set at 320 pixels by 240 pixels. The frame rate should be set at 12 fps.

3. Setting up your Flash environment

For this tutorial, I'll assume that you know how to have Flash display the Actions, Properties, Parameters, and Components windows. I keep them by the side of the workspace because I use them a lot.

4. Adding a label to the document

Open up components and drag a label object onto the document

5. Setting the label properties/parameters

Open up the properties for the label. We need to give the object a name. I've named it "ourLabel". To make it a text field as large as the Chumby screen, I've set the location to x = 0, y = 0, and its dimensions to 320x240.

Just for fun, under the parameters, and make the label an HTML label. It'll ignore tags that way.

6. Action window

Unselect everything. We now need to open up the actions window, and add some action script to make everything actually work. Here's the code that I added:

	url = "http://grouplab.cpsc.ucalgary.ca"; // link to the text
	delay = 1000; // one second refresh rate
	ourLabel.text = "";
	// Start this function on load
	then = 0; // set the initial time
	this.onEnterFrame = function () {
		now = (new Date()).getTime(); // get current time in milliseconds
		if (now-then>delay) { // enough time elapsed since last time loaded?
			doLoadText(); // request text
			then = now; // and reset the last load time
		}
	}
	var lv:LoadVars = new LoadVars();
	lv.onData = function(thetext:String) {
		ourLabel.text = thetext;
	}
	function doLoadText() {
		lv.load(url);  
	}

7. Saving that document

We're done so we might as well save. Remember to save the program as a Flash 8 file, or nothing will work. Every time you save, Flash will try to save it as a CS3 file. You'll have to "Save As..." each time.

8. Generate the .SWF file

You'll need to generate a flash movie.

Goto control and select Test Movie

Assuming everything works, you'll see a window trying to display the Grouplab homepage's text.

Displaying an image in Flash

In our C# example, we showed capturing images and displaying them on the web. This example is slightly different from our last example. It can be done simply in action script.

Simply start a new project. In the Action window, enter this code.

	url =  "http://pages.cpsc.ucalgary.ca/~saul/wiki/uploads/Main/saul-photo.jpg" ; // link to the cam feed
	delay = 5000; // one second refresh rate
	createEmptyMovieClip("image",0); // We'll just create all the components through action script.  This is a EmptyMovieClip called "image"
	//
	then = 0; // set the last time we loaded the image to a really long time ago.
	this.onEnterFrame = function () {
		now = (new Date()).getTime(); // get current time in milliseconds
		if (now-then>delay) { // enough time elapsed since last image loaded?
			doLoadImage(); // load the image
			then = now; // and reset the last load time
		}
	}
	// Load the image
	function doLoadImage() {
		var movie =  eval("image"); // load up the MovieClip we've called "image" 
		movie.loadMovie(url); // load image into it
	}

Go to "Control" and select "Test the Movie." You should get a window that looks like this:

That's all there is to displaying an image on The Chumby. You'll notice that it may flicker slightly when the image refreshes. There is a more sophisticated way to do this so that no flickering occurs, This is explained here.

Getting the values on the Chumby

Here we encounter our first serious “Gotcha” – the Flash Security Settings.

Flash, by default, will not allow an application to access data on another website. Certain data types seem to be freely parsed (like jpegs), while others, like html, Flash needs permission to display. The permission is not a setting from within Flash. Instead, the permission must be given by the webserver.

Here is the relevant file ( Attach:crossdomain.txt rename crossdomain.xml ). Note that this file MUST be placed in the root directory of the website, or it will not work, and the Chumby will be unable to access the page.

If you looked at the file, you will have noticed that the permission is given to Chumby.com. This is because all of the chumby communications go through that website.

This may lead to some unexpected behavior. I’ve seen a chumby not update it’s display despite numerous pings on the webserver from the chumby.com.

Once written, getting a widget on the Chumby is also somewhat tricky.

Here is a step by step guide to uploading a widget:

1. Login to Chumby.com

2. Mouse over "Widgets" and select "Submit a widget"

3. Fill in the details

Note: You will need a 80x60 jpeg as a thumbnail for that widget. I've provided one here.

Remember the category that you uploaded the widget as. Also, ensure that you uploaded it as "private" unless you want others downloading your widget.

4. After uploading, it, move over to "My Chumby" and select "my chumby dashboard"

5. Go and select "Manage Channel" I've previously made an extra channel called "SaulStuff". This is the one I will manage.

6. Go to the category you uploaded the widget to, select it, and choose "ADD WIDGET"

7. Once this is finished you can close your webbrowser and pick up the Chumby.

(insert chumby walk through if this thing ever works again)