Blinking Logfile Map

Nikolaus Gradwohl2010-06-05T18:17:00+02:00

I always wanted to see where the readers of my blog are comming from, so I took a picture frame and inserted a world map, a handfull of leds and an arduino. Some soldering and some rubyscripts later I had my hardware geo-aware logfile visualization.

I have a script running at the server that parses new ip adresses from the log file and geocodes them. Than the continent code is sent to my mac where i have a little script that forwards the continent code to the serial port. And finally the arduino in the picture frame is making the leds blink. The whole project was hacked together as a weekend project so the scripts might need some "fine-tuning" :-)

This is my day 5 project for 30DaysOfCreativity

so please read my blog to make the leds blink :-)

blinklog blinklog

The world map is released under a creative commons licence and cand be downloaded here

The geocoding is done using the iprange to continent mappings from countryipblocks.net

The hardware part looks like this (just some leds and resistors) blinklog

This is the code i'm running on my arduino int count[] = { 0,0,0,0,0,0,0 };

void setup() {
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  Serial.begin( 9600 );
}

void loop() {  
  if (Serial.available() > 0) {
    byte in = Serial.read();
    if (in >= '1') {
      count[ in - '1' ] = 50;
    }
  }
  for( int i =0; i < 7; i++) {
    if (count[i] > 0) {
      digitalWrite( i+2, HIGH);
      count[i]--;
    } else {
      digitalWrite( i+2, LOW);
    }
  }

  delay(10);
}

This is the script that runs on the computer the arduino is connected to

require 'rubygems'
require 'serialport'
require 'socket'
include Socket::Constants
SERIALPORT="/dev/tty.usbserial-A600ag8n"


sp = SerialPort.new( SERIALPORT, 9600, 8, 1, SerialPort::NONE)
sleep(2)
(1..7).each{ |i|
    sp.write( "#{i}"  )
    sleep(0.2)
}

socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, '' )
socket.bind( sockaddr )
socket.listen( 5 )
while(true)
    client, client_sockaddr = socket.accept
    led = client.readline.chomp
    sp.write( led )
    client.close()
end

sp.close()

and this is the script that runns on my server and geocodes the ip adresses

require 'socket'
include Socket::Constants

def ip2int(ip)
    block = ip.split('.')
    ipi = block[0].to_i * 256 * 256 * 256 + block[1].to_i * 256 * 256 + block[2].to_i * 256 + block[3].to_i
    return ipi
end

def parseCountryFile( fn )
    ranges = []
    f = File.new("geocodeip/country_ip/#{fn}")
    f.each_line { |l|
        if l[0] != '#'[0] then
            tmp = l.split("-")
            start = ip2int(tmp[0].strip)
            stop = ip2int(tmp[1].strip)

            ranges << [start, stop]
        end

    }
    return ranges
end

def findIp( map, ip )
    ipi = ip2int( ip )
    map.each{ |continent,ranges|
        ranges.each{ |start,stop|
            return continent if ipi > start and ipi < stop
        }
    }
    return "4"
end

def process( map, line ) 
        t = Thread.new do 
                continent =  findIp( map, line.split(" ")[0])
                socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
                sockaddr = Socket.pack_sockaddr_in( 2200, 'nikkimac' )
                socket.connect( sockaddr )
                socket.puts continent
                socket.close
                puts continent
        end
end

map = {}
map["1"] = parseCountryFile("Oceania_range.txt")
map["2"] = parseCountryFile("Asia_range.txt")
map["3"] = parseCountryFile("India_range.txt")
map["4"] = parseCountryFile("Europe_range.txt")
map["5"] = parseCountryFile("Africa_range.txt")
map["6"] = parseCountryFile("South_America_range.txt")
map["7"] = parseCountryFile("North_America_range.txt")

puts "parsing done ..."

f = File.new( "/var/log/apache2/access.log" )
f.seek( 0, IO::SEEK_END );
last = f.pos
while true
        sleep(1)
        size = f.stat.size
        if last < size then
                l = f.readline
                process( map, l )
                while !f.eof
                        l = f.readline
                        process( map, l )
                end
                last = f.pos
        end
end
Tweet This! submit to reddit Digg!   Tags: | no comments | no trackbacks

See also:

processing ical-flowers-2.0
Day 30 of 30DaysOfCreativity - RadioPI interface module
Day 28 of 30daysofcreativity - testing the radiopi software
Day 26 of 30DaysOfCreativity - prototyping the controls
Day 24 of 30DaysOfCreativity - a breadboard arduino

Trackbacks

Comments

Leave a response

Leave a comment