Aruduino ethernet shield and Rails

I just wrote an article on the GumboLabs blog about using the Arduino Ethernet shield. Be sure to check it out.

Rails app turns seedbox into mediacenter

Well, it has been a while since a post. I am glad to get something back up here. I am just coming coming up for air from a long stretch of work. I wanted to waste a little time so I decided to make an improvement on my custom seedbox / media center. If you want to read a little about it, check this post.

Anyway, what I wanted to do is have a webpage served from my seedbox that displays all the movies on the system with a link to imdb and a link to play the movie. The link to play the movie would create a ‘vlcrc’ subprocess and open up a new window with the controls. This way, anyone on my network, using a laptop or phone, could open up the page and choose a movie and it would play on my TV.

This initially seemed really complicated when I came up with the idea last year and I had started writing a pretty thorough Rails app to do it. Then I got tired of it and forgot about it. Like most code I write, I realized that unless money was involved I am too lazy to do it right and usually settle for a hack.

The hack resulted in this python cgi script:

#!/usr/bin/env python
import cgi
import cgitb
import os, subprocess
cgitb.enable()

MOVIE_DIRECTORY = "/media/MEDIA/media_backup/videos/films"
MY_IP = "192.168.0.100"
VLC_HTTP_LINK = "http://" + MY_IP + ":8080"

form = cgi.FieldStorage()
movie_to_play = form.getvalue('movie')

print "Content-type: text/html"
print

movies = [mov for mov in
os.listdir(MOVIE_DIRECTORY) if (mov[-3:] == 'avi' or mov[-3:] == 'mov' or mov[-3:] == 'mpg')]

# print
print """
<html><head><title>Ben's Movies</title></head><body>
<font size="4" face="Verdana">"""

if movie_to_play:
    command = "vlcrc %s" % MOVIE_DIRECTORY+'/'+movie_to_play
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
    #print process.communicate()
    #retval = subprocess.call(command, 0, None, None, outptr, errptr)
    print """
             <script>
                  window.open('%s','%s','width=400,height=200');
             </script>
          """ % (VLC_HTTP_LINK, movie_to_play)
    print "Playing: "+ movie_to_play

print """
</center><table border="1">
<tr>
<th></th>
<th>Title</th>
<th></th>
<th></th>
</tr>
"""

base_play_link = "http://" + MY_IP + "/cgi-bin/movies.py?movie=%s"
base_imdb_link = 'http://www.imdb.com/find?s=all&q=%s'

i = 1

for mov in movies:
    nice_mov = mov[:-4] #get rid of extension
    nice_mov = nice_mov.replace('_', ' ') #make it more human readble
    imdb_link = base_imdb_link % nice_mov.replace(' ', '+')
    play_link = base_play_link % mov
    print """
          <tr>
              <td>%d</td>
              <td>%s</td>
              <td><a target="_blank" href="%s">IMDB Info</a></td>
              <td><a href="%s">Play</a></td>
          </tr>
          """ % (i, nice_mov, imdb_link, play_link)
    i += 1

print """
</table></center></font></body></html>
"""

For some reason handling the vlc subprocess was not working for me. I am guessing that it has something to do with the permissions that the cgi script have when trying to execute a subprocess? I don’t know and I didn’t fight it too hard. So instead of fixing it, I just wrote a Rails app. You can download it here.

It basically works exactly the same way. First let’s look at the main controller [BTW, please don't make fun of my ruby, it has been a while :) ]. Also, my source code viewer adds IO twice!!??!?! Should just be IO.popen

class MainController < ApplicationController

    MOVIE_DIRECTORY = "/media/MEDIA/media_backup/videos/films"
    MY_IP = "192.168.0.100"
    VLC_HTTP_LINK = "http://" + MY_IP + ":8080"
    BASE_IMDB_LINK  = "http://www.imdb.com/find?s=all&q="

    def index
        @ip = MY_IP
        @vlc_link = VLC_HTTP_LINK
    	@movies = Dir.new(MOVIE_DIRECTORY).entries.find_all{|item| item =~ /.avi$/ or item =~ /.mpg$/ or item =~ /.wmv$/ or item =~ /.mp4$/}
        @movie_to_play = params[:movie]
         if @movie_to_play
	     system("killall vlc")
	     vlcpipe = IO.popen("vlcrc "+MOVIE_DIRECTORY+"/"+@movie_to_play)
         end
    end

end

This is the only controller. It pulls all the movies from the ‘films’ folder on my hard-drive. I name all my movie files by the title with underscores instead of spaces, for example 2001_A_Space_Odyssey.avi. After it gets all the movies, it checks the request for a parameter named ‘movie’. If there is a movie, it kills any instances of vlc, if there are any running, it then runs my little vlcrc bash script. That script ensures the DISPLAY is set to my TV and starts up vlc using the http interface. Once again, refer to my last post.

Next let’s look at the view. First the helper file:

module MainHelper

    def nice_name(movie)
    	movie[0..movie.length-5].gsub('_', ' ')
    end

    def imdb_link(movie)
        link = "http://www.imdb.com/find?s=all&q="+movie.gsub('_', '+')[0..movie.length-5]
    	return "<a href='"+link+"' target='_blank'>IMDB Info</a>"
    end

    def play_link(movie)
    	"<a href='/main/index?movie="+movie+"'>Play</a>"
    end

end

Then the index.html.erb template:

<html>
  <head>
    <title>Ben's Movies</title>
  </head>
  <body>
  <font size="4" face="Verdana">

   <center>
     <h2> There are currently <%= @movies.length %> movies on this machine </h2>
    <% if @movie_to_play %>
	   <div style="background-color:#9ACD32; color:#FFFFFF; visibility: visible"><p>Now Playing <b><%= @movie_to_play %></b></p></div>
           <script>
                 function open_vlc_window() {
                    window.open('<%= @vlc_link %>','<%= @movie_to_play %>','width=600,height=385');
                 }
                 setTimeout("open_vlc_window()",1250);//slight delay, vlc needs a second to start up
           </script>
        <% end %>
        <table border=1>

          <% @movies.each do |movie| %>
              <tr>
                 <td><%= nice_name(movie) %></td>
                 <td><%= imdb_link(movie) %></td>
                 <td><%= play_link(movie) %></td>
              </tr>
          <% end %>

        </table>
        </center>
      </font>
    </body>
</html>

Ugh, ugly code, useless declarations, poor ruby practices, oh well. Anyways, how it works should be pretty obvious. I had previously written a service to pull down the synopsis info for a movie but all that was too complicated so i just made the link a search on imdb. If the movie name is unique, it will jump straight to the page, if not, it will ask you to choose between movies with the same or similar names by just executing a standard search.

Here is the home page:

Home Page

Home Page

Then we click play on Adaptation:

Play button pushed

Play button pushed

It informs us of the movie that is playing with the green status bar and the ajax remote control box pop up. It is sized to be as small as needed:

vlc control interface

vlc control interface

You can play, stop, pause, toggle fullscreen, change the volume, and there is even a seek bar. The best thing about it is that this is all javascript so it works pretty well on all browsers, even phone browsers. It fits nicely on my G1 :)

If you click on another movie, the vlc instance is killed as expected and a new one is started. All that is left to do is create an init.d bash script to start up the mongrel server on port 80 on boot up and maybe map your ip to a name if you have the means.

Parallax RFID reader <--> Arduino

Parallax RFID reader

Parallax RFID reader

I just recently wrote an article at the Gumbo Labs blog on interfacing to the Parallax RFID reader. Here is the final code if you are only looking for that:

/**
 * author Benjamin Eckel
 * date 10-17-2009
 *
 */
#define RFID_ENABLE 2   //to RFID ENABLE
#define CODE_LEN 10      //Max length of RFID tag
#define VALIDATE_TAG 1  //should we validate tag?
#define VALIDATE_LENGTH  200 //maximum reads b/w tag read and validate
#define ITERATION_LENGTH 2000 //time, in ms, given to the user to move hand away
#define START_BYTE 0x0A
#define STOP_BYTE 0x0D

char tag[CODE_LEN];  

void setup() {
  Serial.begin(2400);
  pinMode(RFID_ENABLE,OUTPUT);
}

void loop() {
  enableRFID();
  getRFIDTag();
  if(isCodeValid()) {
    disableRFID();
    sendCode();
    delay(ITERATION_LENGTH);
  } else {
    disableRFID();
    Serial.println("Got some noise");
  }
  Serial.flush();
  clearCode();
} 

/**
 * Clears out the memory space for the tag to 0s.
 */
void clearCode() {
  for(int i=0; i<CODE_LEN; i++) {
    tag[i] = 0;
  }
}

/**
 * Sends the tag to the computer.
 */
void sendCode() {
    Serial.print("TAG:");
    //Serial.println(tag);
    for(int i=0; i<CODE_LEN; i++) {
      Serial.print(tag[i]);
    }
}

/**************************************************************/
/********************   RFID Functions  ***********************/
/**************************************************************/

void enableRFID() {
   digitalWrite(RFID_ENABLE, LOW);
}

void disableRFID() {
   digitalWrite(RFID_ENABLE, HIGH);
}

/**
 * Blocking function, waits for and gets the RFID tag.
 */
void getRFIDTag() {
  byte next_byte;
  while(Serial.available() <= 0) {}
  if((next_byte = Serial.read()) == START_BYTE) {
    byte bytesread = 0;
    while(bytesread < CODE_LEN) {
      if(Serial.available() > 0) { //wait for the next byte
          if((next_byte = Serial.read()) == STOP_BYTE) break;
          tag[bytesread++] = next_byte;
      }
    }
  }
}

/**
 * Waits for the next incoming tag to see if it matches
 * the current tag.
 */
boolean isCodeValid() {
  byte next_byte;
  int count = 0;
  while (Serial.available() < 2) {  //there is already a STOP_BYTE in buffer
    delay(1); //probably not a very pure millisecond
    if(count++ > VALIDATE_LENGTH) return false;
  }
  Serial.read(); //throw away extra STOP_BYTE
  if ((next_byte = Serial.read()) == START_BYTE) {
    byte bytes_read = 0;
    while (bytes_read < CODE_LEN) {
      if (Serial.available() > 0) { //wait for the next byte
          if ((next_byte = Serial.read()) == STOP_BYTE) break;
          if (tag[bytes_read++] != next_byte) return false;
      }
    }
  }
  return true;
}

Hacking the Asus WL-520GU w/ OpenWRT

Check out my post over at GumboLabs about hacking the Asus WL-520gu with openWRT. I am in the process over creating a wireless home power monitoring system that connects to pachube. I have been really busy at work and other projects lately so it may not happen for a while, if at all.

I am going to be writing a few articles on the GumboLabs blog from time to time to help get it going and hopefully get a small readership. I will be posting links from here.

New Orleans Hackerspace — Gumbo Labs

I have been putting off mentioning this, but we have started a hackerspace in New Orleans dubbed Gumbo Labs [http://www.gumbolabs.org/]. We are located at the end of Banks St. in a warehouse by the graveyard. To get more info join the mailing list. Also, be sure to watch for updates on the blog [http://www.gumbolabs.org/cms].

WarioWare Twisted + QTAR

I have been thinking about designing, coding, and building a quad copter for a long time. I think I am finally at a level of experience and financial security to give it a run. In the mean time, I got a Silverlit x-ufo off with a broken mechanical gyro off ebay and did a plottermeier mod. I just wanted to start fooling around with a quadrotor to get used to some of the controls and terminologies. I got the electronic gyros from two WarioWare Twisted games : http://en.wikipedia.org/wiki/WarioWare_Twisted!. Here’s a video.

Calculate current limiting resistors for LEDs

As I was learning about electronics, the use of the current limiting resistor came up a lot. Too often instructors neglect to explain how to properly calculate the value of the resistor. Either they would not explain anything at all or they would leave out the effects of the voltage drop of the component. It is really pretty easy and it eventually becomes important; so, you should know this. This is most often used when hooking up an LED so we are going to use that as an example.

Here is the most bare-bones circuit you would use to light an LED:

dropdownwrong1

Now, if you actually hook this up, you are going to have a problem. Without any kind of significant resistance in the circuit, the LED is going to run free and draw a lot of current in a small amount of time. In most cases, it will burn out and will never light to it’s full potential again. Remember that 0 Ohms of resistance in a circuit is a bad thing! In order to supply the right amount of current to the LED, we need a circuit like this:

dropdown

The value of the resistor depends on a number of things.

  1. How much current the LED needs (can be different for all LEDs)
  2. The voltage drop of the LED (can also be different for all LEDs)
  3. Your actual supply voltage (should be measured with a multimeter and verified as stable to be sure)

Let’s say you have a small red LED. According to the specs, it needs 20 milliamps (0.02 Amps) and has a voltage drop of 1.7 V. To calculate the needed resistance, we need Ohm’s Law. In as simple of terms as possible, it says that Voltage [V] in (Volts) = Current [I] (in Amps) times Resistance [R] (in Ohms). Or more appropriately for our scenario,

R = V/I

In order to calculate this correctly, you need to obtain V by subtracting the LED voltage drop from the supply voltage [I often hear instructors ignore this part and just use the supply voltage for V, FAIL]. So, if we have a supply of 5V and a drop of 1.7V, V should be 5-1.7 or 3.3V. Since I is 0.02 Amps, R becomes 3.3/0.02 or 165 Ohms. See, this is first grade mathematics! If you can’t find the exact value resistor on the market, you generally want to round it up to be safe. It is always better to supply less current to the component than it is to let the component pull more than it needs. The closest I could find for this scenario was 180 Ohms.

One more thing you may want to consider is the the amount of current you actually wish to supply to the LED. Your datasheet might tell you it needs 20 mA, but you may often find that giving it about 75% of it’s recommended current usually produces no visible difference from full saturation. Do some experimenting to see how much current you actually want to give your LED. You will quickly find that the ratio of brightness to current is not directly proportional and not a ratio at all. My best guess is that it is some kind of logarithmic relationship. So, assuming you want to power this LED at 15 mA, your new resistance value is 220 Ohms. The more LEDs you have, the more important it is to get these values right. If I get the chance, my next post will explain different configurations for hooking up multiple LEDs.

Creating a remote seedbox / mediabox / webserver from an old PC

I know a lot of people have covered this, but I thought I would share my process behind creating my little multifunctional webserver. I had an old tower that I wasn’t really using. It has an Intel chip (Celeron possibly?), 2G of memory, and 2 hard drives [50GB and 500GB]. I also have a decent Nvidia video card with DVI output. I originally just used it as a mediabox. I had it hooked up to my TV, I ripped Netflix movies on my OS X machine using handbrake into an AVI format, then I put them on this system [which is running Ubuntu] and played them using VLC. This was all well and good, but I didn’t like the idea of having a mouse and keyboard hanging around all the time. So I turned to VLC’s command line interface. After playing around for a while, I was able to get the http interface working. I created an alias in my ~/.bashrc as a little macro :

alias vlcrc='export DISPLAY=:0 ; vlc -I http --no-media-library'

** The DISPLAY=:0 may or may not be necessary to get your video card to display to the attached monitor or TV **

After this, I setup SSH for Ubuntu. Then I gave the Ubuntu machine a static ip address [192.168.0.100] through my router’s admin interface [instructions depend on router, GIYF]. Now, from my laptop connected to the same network over Wifi,  I am able to SSH into the mediabox, and run something like this:

vlcrc There_Will_Be_Blood.avi

Then I can open up Firefox and go to this URL:

http://192.168.0.100:8080/

and I am presented with this beautiful javascript interface:

vlc_interface1

It allows you to control everything in your VLC instance like volume, position, fullscreen, pause/play, and etc just like a remote control. The coolest thing for me was that I could control this with my G1 :) If you try this and get a 403 error, you need to configure your .hosts file. Look here : http://www.videolan.org/developers/vlc/NEWS and do a browser search for ‘.hosts’ to see the instructions. You just need to add IPs of computers that want access to the http interface to a whitelist. I just added a bunch of IPs between 192.168.0.101 and 110 b/c I knew my laptops would never get assigned anything out of that range. By this point, I was able to hide the PC behind my TV and not worry about connecting a mouse and keyboard to it. I was able to pick up a DVI to HDMI cable for 10 dollars at Optimized Cable. They are cheap, but adhere to the HDMI 1.3b standard and as long as they are 6 feet or under, you shouldn’t be able to tell the difference between these and the expensive Monster cables.

From here I started to setup the Torrent side of the box. Ubuntu now comes with Transmission which is arguably one of the best clients around. To save yourself from problems later on, make sure it is upgraded to something over 1.5. If you need to update, go to getdeb.net and get transmission-common and transmission-gtk. Download and install them in that order. After you run it, you can go to Preferences –> Web and setup the web interface. I set mine up on port 9091 and then went to this URL from my laptop:

http://192.168.0.100:9091

You are then presented with a cool interface for uploading, controlling, and monitoring your torrents:

transmission_interface

This was really helpful but I soon wanted a little more functionality. Wouldn’t it be cool if I could control this from anywhere on the net? Of course. For that, I needed to make this computer visible to net.

The thing that makes this part difficult is the way in which most residential users access the internet. As you may know, accessing a domain name, like datasingularity.com, requires a DNS lookup to find the IP address that the domain is referring to. The problem is that most people don’t keep the same IP address for very long. Much like DHCP on your router, your ISP often assigns you different IPs when you connect to their network. This is called having a dynamic IP as opposed to having a static ‘non-changing’ IP. Since your IP is not always the same, registering a domain for your current IP in some nameservers may not last long. If you are not on a business network and don’t know if you have a static or dynamic IP, we can just assume that you have a dynamic IP. That is why you need the DynDNS service. They constantly update your DNS information for you. You just install a client on your webserver and it tells their service when your IP changes. Kick ass.

You can get a free domain like mydomainname.homelinux.net, or you can pay for a custom one. I went ahead and signed up then registered a free domain. I then followed the instructions at this informative link : http://mexpolk.wordpress.com/2008/01/29/ubuntu-gutsy-dyndns-client-setup/.Then I went to this link :
http://www.portforward.com/routers.htm to set up port forwarding on my DLink DI-604 ethernet router. The first port I set up was port 22. This now allows me to SSH and SFTP to my home computer. Yessss. Then I forwarded the 9091 port to get to my Transmission web interface. If your router supports it, you can forward from port external 80 to port 9091 internal, that way, you can just go here:

http://mydomain.homelinux.net

and it takes you straight to the interface! Otherwise, you need to forward 9091 external to 9091 internal and go here:

http://mydomain.homelinux.net:9091

If you want this to be a regular webserver at the same time, it is best to leave port 80 clear and just use 9091. You have to ensure a few things in your Transmission client. Make sure that you go to Preferences –> Web tab and set it up to require a username and password. You don’t want anyone on the net to just go in and mess with your torrents! Then make sure you disable the IP whitelist so any IP can access it. I think it is just a checkbox somewhere in the Preferences –> Web tab.

I am currently in the process of creating a Rails web application to be served locally. It basically holds all the metadata for my media [tied to imdb web service] and lets me browse my system from another web browser on the same network. I can then click a movie or TV show to play it. It launches a VLC process and the HTTP javascript interface in a new browser window! Not done yet but will keep anyone interested updated.

I am somewhat of an idiot when it comes to security, so anyone please chime in if you see any obvious problems here. Any comments, tips, or criticisms are appreciated.