[perl plack psgi] WebアプリをWebサーバから抽象化

WebアプリをWebサーバから抽象化する事により、

1. Webアプリ側ではどのWebサーバで実行するかを考える事なく
1つのインターフェースに対応させればよい

2.Webサーバ側でも抽象化された1つのインターフェースに対応すればよい


故に開発の負担が減り本来のアプリケーションの機能向上に専念できる。
などのメリットからWebサーバインターフェイスの統一化の流れが進んでいます。


まずPytonでPEP333 WSGIが定義されました。


次にRubyの世界で、
アプリケーションサーバMongrelやThin,Passengerなど多くのサーバに対し
WAFの対応を統一する為にRackが定義されました。
RailsがCGIに代えて、WebサーバインターフェースRackをサポートした事は有名です。


Perlの世界でも同じような潮流が起きています。
HTTP::Engineがその先駆けでした。
しかしWAFによっては対応が難しい場合もあり、

1.仕様 PSGI
2.実装 Plack

と分割し各サーバへの対応はアダプターで対応
としPlackが誕生しました。

以下のサイトで詳しく紹介されています。
Perl Superglue Web Frameworks and Web Servers

Plackの魅力は、WebアプリをWebサーバから抽象化だけに留まりません。


1. perlを使って簡単にwebミニアプリが作れるように作りました。

plackupを使えばwebサーバとしても機能するのでお手軽にperlでミニアプリが作成できます。

Plack::Requestとか使って小さなWebアプリを作ろう!

簡易GyazoサーバをPlackで実装したら27行くらいで書けた


2. リアルタイムAPI、リアルタイムWebに対応

psgi.streamingやpsgi.nonblockingでlongpollやMXHRと相性がよい
PSGIに対応してるTatsumakiフレームワークのサンプルを確認すると
簡単にNon-blocking webが実装できる事がわかります。

multipart/mixedなストリームをPlack/PSGIでpushする
Tatsumakiのdemoプログラム解析

参考サイト:
5分でわかるRack
CGI から Mongrel まで、Rack で Web アプリを Web サーバから抽象化する
Rack日本語リファレンス
Ruby Freaks Lounge 第25回 Rackとは何か(3)ミドルウェアのすすめ
Perl PSGI Plack | Webフレームワーク ウェブサーバの抽象化


PHPではrack-php
みたいなのが出来てますが、そもものWeb用の言語として始まったので
あまり必要性がないかもしれません。

AIR2.0のNativeProcessを使って
jQuery PluginのCOLOR PICKERで選択した色をPerl経由でArduinoに送り
LEDの色を変化させる。

[AIR2.0 ajax] NativeProcessで perl を呼び出す メモをベースにします。

1. JQUERY PLUGINを落としてきて配置
COLOR PICKER - JQUERY PLUGINからダウンロードして配置します。
今回は以下のように配置しました。
picker1

2. COLOR PICKERをHTMLに表示する
picker3
でCOLOR PICKERを読み込みます。

javascriptで以下のように記述します。
$(function(){
  $('#colorpickerHolder').ColorPicker({flat: true,
     color: '#000000',
     onChange: function (hsb, hex, rgb) {
         writeData(hex);
     }
   });
});

bodyの中に

を記載します。

picker2

3. ArduinoにFF0000などの文字列を送るとBlinkMの色が変わるプログラムを送信します
#include "Wire.h"
#include "BlinkM_funcs.h"<<<<>>>>
#define BLINKM_ARDUINO_POWERED 1

byte blinkm_addr = 0x00;  
char serInStr[30];

void setup()
{
    if( BLINKM_ARDUINO_POWERED ) {
        BlinkM_beginWithPower();
    } else {
        BlinkM_begin();
    }
 
    Serial.begin(19200);

    // stop seq
    BlinkM_stopScript( blinkm_addr );
    
    // set default color
    BlinkM_setRGB( blinkm_addr, 0xff,0xff,0xff); // white
    
    // fade time
    BlinkM_setFadeSpeed( blinkm_addr, 255);
    
    // change color
    BlinkM_fadeToRGB( blinkm_addr, 0x00,0x00,0x00); //black

}

void loop()
{
	
  int num;
  if( readSerialString() ) {
    //Serial.println(serInStr);
    char* str = serInStr;
    num = atoi(str);
    byte a = toHex( str[0],str[1] );
    byte b = toHex( str[2],str[3] );
    byte c = toHex( str[4],str[5] );
     BlinkM_fadeToRGB( blinkm_addr, a,b,c);
  }
}

#include <ctype.h>
uint8_t toHex(char hi, char lo)
{
  uint8_t b;
  hi = toupper(hi);
  if( isxdigit(hi) ) {
    if( hi > '9' ) hi -= 7;      // software offset for A-F
    hi -= 0x30;                  // subtract ASCII offset
    b = hi<<4;
    lo = toupper(lo);
    if( isxdigit(lo) ) {
      if( lo > '9' ) lo -= 7;  // software offset for A-F
      lo -= 0x30;              // subtract ASCII offset
      b = b + lo;
      return b;
    } // else error
  }  // else error
  return 0;
}

uint8_t readSerialString()
{
  if(!Serial.available()) {
    return 0;
  }
  delay(10);
  int i = 0;
  while (Serial.available()) {
    serInStr[i] = Serial.read();
    i++;
  }
  serInStr[i] = 0;
  return i;
}
4. AIRのプログラムをAjaxスタイルで書きます
air2
jQueryColorPickerで色を選択したらNativeProcess経由でAnyEventで
標準入力に色コードをFF0000を送り、 Device::SerialPortでArduinoに
色データを送信します。

index.htmlは
<html>
<head>
<title>jQuery Plugin Color Picker - Perl - Arduino - BlinkM</title>

<link rel="stylesheet" type="text/css" href="css/colorpicker.css" />
<link href="css/layout.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/colorpicker.js"></script>

<script type="text/javascript" src="AIRIntrospector.js"></script>

<script type="text/javascript" src="AIRAliases.js"></script>
<script type="text/javascript"> 
var process;
var selected_hex;

function init(){ // Introspectorを起動しない//
  air.Introspector.canInit = function () { return false };
  air.Introspector.Console.log("Hello!");

  if (air.NativeProcess.isSupported){
   // windowをクローズする時に呼ばれるイベント
    window.nativeWindow.addEventListener(air.Event.CLOSING, closingHandler);
    launchEchoTest();
  }else{
    var textReceived = document.getElementById("textReceived");
    textReceived.value = "NativeProcess not supported.";
  }
}

// windowをクローズする時に呼ばれるイベント
function closingHandler(event){
  process.closeInput();
  window.nativeWindow.close();
}

function launchEchoTest(){	 
  var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
  nativeProcessStartupInfo.executable = new air.File(air.File.applicationDirectory.nativePath + "/perl/serial.pl");    
  process = new air.NativeProcess();
  process.addEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
  process.addEventListener(air.ProgressEvent.STANDARD_INPUT_PROGRESS, inputProgressListener);
  process.start(nativeProcessStartupInfo);
}

function writeData(selected_hex){
  process.standardInput.writeUTFBytes(selected_hex + "\n");
}

function inputProgressListener(event){
  //process.closeInput();
}

function onOutputData(event){
  var bytes = process.standardOutput;
  $('#messages').prepend( bytes.readUTFBytes(bytes.bytesAvailable) );
}

$(function(){
  init();
  $('#colorpickerHolder').ColorPicker({flat: true,
                                       color: '#000000',
                                       onChange: function (hsb, hex, rgb) {
                                         writeData(hex);
                                       }
  });

});
</script>

<style>
#colorpickerHolder {
  top: 0px;
  left: 0px;
  width: 380px; 
}
#messages {
  position:absolute;
  top: 0px;
  right: 0px;
  height: 170px;
  width: 100px; 
  overflow: auto;
}

body {
  margin: 0 0;
}
</style>
</head>
<body> 
<div id="messages"></div>
<div id="colorpickerHolder"></div>
</body>
</html>
NativeProcessで起動されるPerlのスクリプトは以下のようになります。
Serial.pl
#!/usr/bin/perl
use strict;
use Device::SerialPort;
use AnyEvent;

# Arduino 
my $p = Device::SerialPort->new("/dev/tty.usbserial-A8004JhW");
$p->databits(8);
$p->baudrate(19200);
$p->parity("none");
$p->stopbits(1);
sleep(3); # For Arduino bootup wait.

use utf8;
binmode STDIN,  ":utf8";
binmode STDOUT, ":utf8";

$| = 1;
my $cv = AnyEvent->condvar;
my $w; $w = AnyEvent->io(
    fh   => \*STDIN,
    poll => 'r',
    cb   => sub {
        chomp(my $input = <STDIN>);
        $cv->send if(!$input); 
	 $p->write($input . "\n");
        print "DONE:" . $input . "\n";
    },
    );
$cv->recv;
5. AIR2のパッケージを作成する
$adt -package -storetype pkcs12 -keystore myCert.p12 -target native NativeProcessTest.dmg application.xml index.html AIRAliases.js  icons perl/serial.pl css js images
AIRのアプリをインストールし実行すると
ColorPickerを選ぶとLEDの色が変化しているのが確認できます。
AIR2.0 NativeProcess AnyEvent USB Serial Arduino BlinkM
AIR2.0 Arduino BlinkM

[mtos5] ubuntuにmtos5をインストール メモ

  • 投稿日:
  • by
  • カテゴリ:
mtos5が出ていたので試してみるメモ

1. mysqlのアカウントの作成
mysql> create database mtos;
mysql> GRANT ALL ON *.* TO mtos@"localhost" IDENTIFIED BY "1234";
mysql> FLUSH PRIVILEGES;

2. mtosのファイルを設置
MTOS: Movable Type オープンソース・プロジェクトから
mtosをダウンロードを行い設置しパーミッションをwebサーバが書き込める状態にする
mtos
$ chmod 777 mt

3. apacheの設定をする
ubuntu(debian)の流儀に従って
/etc/apache2/sites-availableに定義ファイルを作成します
<VirtualHost *:80>
    ServerAdmin max@de4u.net
    ServerName mtos.yoshimax.net

    DocumentRoot /home/www/mtos/htdocs/mt/
    Alias /memo /home/www/mtos/htdocs/memo/

    <Directory /home/www/mtos/htdocs/mt>
        AddHandler cgi-script .cgi
        Options +ExecCGI
        AllowOverride None
        DirectoryIndex index.html
        Order allow,deny
        allow from all
    </Directory>
</VirtualHost>

シンボリックリンクを貼って有効にし、 Apacheを再起動します。
# ln -s ../sites-available/mtos 002-mtos
# /etc/init.d/apache2 restart

4. web画面からmtのインストールを開始します
初期画面 言語を選択
mtos1

mtos2

mtos3

必要要件を満たしているか確認画面です
mtos4

1.で作成作成したmysqlのアカウントを記入します
mtos5

mtos6

mtos7

パーミッションがないとエラーになるので注意!
mtos8

ユーザーアカウントを作成します
mtos9

最初のウェブサイトの設定をします。
mtos5では、ウェブサイトの下層にblogを作成するスタイルですので
各々のblogへのポータルサイトのようなページになります。
mtos10

インストールが実行されます
mtos11

インストールの完了です
mtos12

入力画面のデザインが変更されたのでキャプチャを幾つか載せます。
mtos13

mtos14

mtos15

ウェブページがトップにありその下層にblogが作成されているのが確認できます。 mtos16
最近の流行のircサーバが分からないので、
とりあえず昔使った事がある irc-hybridをubuntu server 9.10にインストール メモ

1. aptでインストールする
#apt-get install ircd-hybrid
irc-hybrid_1

2. 設定ファイルの位置を確認する
dpkg -L ircd-hybrid |grep etc
irc-hybrid_2
/etc/ircd-hybrid/ircd.conf
に設定したいファイルがある事がわかる

3.設定する
今回はサーバーはローカル10.0.1.100に設置しており、
ルーターのポートフォワードでグローバルから転送する
irc-hybrid_3
listenの部分を変更してIPアドレスとポートを決めます
ここでは、一般的な6667に設定します。
irc-hybrid_5

今回利用する内部IPで
denyの設定がされおり
irc-hybrid_7
01:06 Connecting...
01:06 Connected
01:06 NICK yoshimax
01:06 USER yoshimax 8 * :yoshimax
01:06 Error: You have been D-lined.
01:06 Broken pipe
01:06 Disconnected
この様なエラーがでて大変ハマりました。
denyの部分はとりあえずコメントアウトしておきます。

4.ファイヤーウォールやルータでポートの設定をする
今回は内部IPなのでファイヤーウォールは設定していませんが、
グローバルIPからポートフォワードしています。
irc-hybrid_4

5.起動する
# /etc/init.d/ircd-hybrid restart


6. クライアントから接続する
irc-hybrid_8

7. パスワード制限をする
authの部分にpasswordを設定します。
サーバのパスワードになるようです。
(ユーザだと思っててかなりハマりました。)
irc-hybrid_6
Arduino: Playground のCode for using the Arduino with the P*rall*x RFID readerのサンプルを利用し
Parallax brand RFID readerのデータをUSBシリアル接続されたArduinoで取得してみます。

1. 配線
Parallax RFID Reader Serialを以下のように接続します。
Arduino             RFID Reader
Arduino GND              -  GND
Arduino 5V                  -  VCC
DIGITAL2     -  ENABLE
DIGITAL8     -  SOUT

写真でみると以下のようになります。 Arduino RFID

2. Arduinoのプログラムを書く
読み込んだ値をmacにUSBシリアルで転送させたいので
0(RX),1(TX)のピンは利用できないので、
他のポートをソフトウェアでシリアル化して読み込みます。
ここでは、Arduino: Playground のCode for using the Arduino with the P*rall*x RFID readerのサンプルを利用します。
// RFID reader for Arduino 
// Wiring version by BARRAGAN  
// Modified for Arudino by djmatic
// Modified by Worapoht K.
// http://www.arduino.cc/playground/Learning/PRFID のサンプルを利用
 
#include 

int  val = 0; 
char code[10]; 
int bytesread = 0; 

#define rxPin 8
#define txPin 9
// RFID reader SOUT pin connected to Serial RX pin at 2400bps to pin8

void setup()
{ 
  Serial.begin(9600);  // Hardware serial for Monitor 9600bps

  pinMode(2,OUTPUT);       // Set digital pin 2 as OUTPUT to connect it to the RFID /ENABLE pin 
  digitalWrite(2, LOW);    // Activate the RFID reader 
}


void loop()
{ 
  SoftwareSerial RFID = SoftwareSerial(rxPin,txPin); 
  RFID.begin(2400);

  if((val = RFID.read()) == 10)
  {   // check for header 
    bytesread = 0; 
    while(bytesread<10)
    {  // read 10 digit code 
      val = RFID.read(); 
      if((val == 10)||(val == 13))
      {  // if header or stop bytes before the 10 digit reading 
        break;                       // stop reading 
      } 
      code[bytesread] = val;         // add the digit           
      bytesread++;                   // ready to read next digit  
    } 

    if(bytesread == 10)
    {  // if 10 digit read is complete 
      Serial.print(code);            // print the TAG code 
    }
    bytesread = 0; 
    delay(500);                       // wait for a second
  } 
} 

Arduinoにスケッチを転送して、シリアルモニタで確認すると
以下のようにRFIDをリーダにかざした時に値が取得できる事が確認できます。
serial rfid

3. Device::SerialPortを利用してRFIDの値を読み込みます。
Quick & Easy Temperature Logging with the Arduinoのサンプルを参考に以下のように書いてみます。
#!/usr/bin/perl                                                                     
use strict;
use warnings;
use Device::SerialPort;

my $dev = tie (*FH, 'Device::SerialPort', "/dev/tty.usbserial-A8004JhW")
    || die "Can't tie: $!";

$dev->baudrate(9600);
$dev->databits(8);
$dev->parity("none");
$dev->stopbits(1);

# wait for arduino to boot                                                          
while (1) {
    my $val = <FH>;
    last if $val;
}

while (1) {
    my $val = <FH>;
    next unless $val;
    chomp $val;
    print $val . "\n";
    #sleep 1;                                                                       
}

実行すると以下のように値を受け取ります。
arduino RFID

値が読み込める事が確認できました。
ただしwhileで回していてCPUの負荷が高いようです。

試しにAnyEventを利用してみます。
AnyEventでtail -fを参考にし、AnyEvent::Handleを利用して書き直しました。
serialからの入力の読み込み方法がよく理解できてないので
無理矢理 IO::Handle Object を取り出してます。
ソースが正しいか分かはわからないですが、
以下のようにRFIDの値が読み込める事は確認できました。
perl serial anyevent
ソースはこちら、
#!/usr/bin/perl                                                                            
use strict;
use warnings;
use Device::SerialPort;

use AnyEvent;
use AnyEvent::Handle;

my $dev = tie (*FH, 'Device::SerialPort', "/dev/tty.usbserial-A8004JhW")
    || die "Can't tie: $!";

$dev->baudrate(9600);
$dev->databits(8);
$dev->parity("none");
$dev->stopbits(1);

# wait for arduino to boot                                                                 
while (1) {
    my $val = <FH>;
    last if $val;
}

# make anyevent loop                                                                       
my $fh = $dev->{'HANDLE'}; #IO::Handle Object                                              
$| = 1;

my $cv = AE::cv;
my $handle = create_handle();

sub create_handle {
    new AnyEvent::Handle
        fh => $fh,
        on_error => sub {
            my ($handle, $fatal, $message) = @_;
            $handle->destroy;
            undef $handle;
            $cv->send("$fatal: $message");
    },
    on_read => sub {
        my $handle = shift;
        $handle->push_read(line => sub {
            my ($handle, $line) = @_;
            print "$line\n";
                           })
    };
}

$cv->recv;

selectで待ち受けしてるみたいですが、
RFIDカードを読み取るとなんかエラーでてるような。
時間があるときに追ってみます。。。
anyevent

参考にさせていただいたサイト
Code for using the Arduino with the Parallax RFID reader
Quick & Easy Temperature Logging with the Arduino
[Arduino XBee Processing] RFIDタグを無線でPCに取り込む
AnyEventでtail -f

MovableTypeのコメント欄をDISQUSに変更してみました。
MTのプラグインになっていて簡単に変更できたのでメモを残します。


1. DISQUSに登録する

disqus_1
登録するとmovable typeのプラグインを落とす画面があるので
そこからプラグインを落とします。

2. movable typeのpluginディレクトリにプラグインをコピーします

disqus_2
コピーして管理画面をリロードするとインストールの初期画面が現れます。

3. インストールします。

disqus_3

4. ブログに入りプラグインの一覧からDISQUSをインストールします。

disqus_4

5. 設定画面

disqus_5
インストールが終わって再構築するだけで既存のコメントがDISQUSのものに置き換わります。

6. プラグインの画面からコメントの管理が可能です

disqus_6

7. コメント画面を確認

disqus_7

コメント画面が置き換わっているのが確認できます。


#追記 20091213
既存にコメントがある場合のMTのコメントをDISQUSに移転してみます。
1000くらいのコメントがあるMTで試してみました。


A. プラグインインストール直後の状態

Disqus1
インストール状態ではコメントは移転されていません。


B. コメントをDISQUSに転送

Disqus2

該当blogのプラグインのDISQUSの設定からインポートボタンをクリックします。


C. インポートの確認

Disqus3


D. インポートの完了

Disqus4
問題なくインポートが出来たら上記の完了画面が表示されます。


E. DISQUS でコメントを確認

Disqus5
コメントが移転できてるのが確認できます。

マイクロソフトが提供しているRemote Desktop Connection Client for Mac 2を使います。

1.
Remote Desktop Connection Client for Mac 2のサイトに行きます。
RemoteDesktopConnectionClientMac1
Remote Desktop Connection のダウンロードをクリックします。

2.
RemoteDesktopConnectionClientMac2
製品別ダウンロードの真ん中のMicrosoft Remote Desktop Connection Client for Mac 2.0.1をクリックします。

3.
RemoteDesktopConnectionClientMac3
詳細に
リリース日 : 2009 年 8 月 11 日
.dmg ファイル サイズ : 7.8 MB
56K モデム : 0 時間 40 分
 Japanese (.dmg)

が表示されるのでJapanese (.dmg)をダウンロードします。

4.
RemoteDesktopConnectionClientMac4
インストーラが起動するのインストールします。

5.
RemoteDesktopConnectionClientMac5
インストールが完了したら、リモートデスクトップを起動して
接続先のIPを入力します。

以上で完了です。
twitterで任意につけたハッシュタグとRGBの指定で、
USBシリアルで接続されたArduinoのBlinkMの色を変更させてみるメモ

今回は [ff0000] #testhoge1 のようにツイートするとUSBシリアルで接続された
ArduinoのBlinkMの色が変更するプログラムを書いてみます。
twitterのリアルタイムAPIを利用して実装してゆきます。

1. ArduinoとBlinkMの設定
[perl mac serial] Device::SerialPortでArduinoに信号を送る メモ
を参考にArduinoのプログラムを書きます。

今回もBlinkMのサイトのサンプルからBlinkM_funcs.hを利用させていただきます。
初期化で消灯し、色の変化を瞬時に変わる設定を行い、
待受ループでシリアルからRGBの色指定が送信されてくるのを待ちます。
#include "Wire.h"
#include "BlinkM_funcs.h"

#define BLINKM_ARDUINO_POWERED 1

byte blinkm_addr = 0x00;  
char serInStr[30];

void setup()
{
    if( BLINKM_ARDUINO_POWERED ) {
        BlinkM_beginWithPower();
    } else {
        BlinkM_begin();
    }
 
    Serial.begin(19200);
    //Serial.print("start");
   
    // stop seq
    BlinkM_stopScript( blinkm_addr );
    
    // set default color
    BlinkM_setRGB( blinkm_addr, 0xff,0xff,0xff); // white
    
    // fade time
    BlinkM_setFadeSpeed( blinkm_addr, 255);
    
    // change color
    BlinkM_fadeToRGB( blinkm_addr, 0x00,0x00,0x00); //red

}

void loop()
{
	
  int num;
  if( readSerialString() ) {
    //Serial.println(serInStr);
    char* str = serInStr;
    //while( *++str == ' ' );
    num = atoi(str);
    byte a = toHex( str[0],str[1] );
    byte b = toHex( str[2],str[3] );
    byte c = toHex( str[4],str[5] );
    //Serial.print("Fade to r,g,b:");
     BlinkM_fadeToRGB( blinkm_addr, a,b,c);
  }
}

#include 
uint8_t toHex(char hi, char lo)
{
  uint8_t b;
  hi = toupper(hi);
  if( isxdigit(hi) ) {
    if( hi > '9' ) hi -= 7;      // software offset for A-F
    hi -= 0x30;                  // subtract ASCII offset
    b = hi<<4;
    lo = toupper(lo);
    if( isxdigit(lo) ) {
      if( lo > '9' ) lo -= 7;  // software offset for A-F
      lo -= 0x30;              // subtract ASCII offset
      b = b + lo;
      return b;
    } // else error
  }  // else error
  return 0;
}

uint8_t readSerialString()
{
  if(!Serial.available()) {
    return 0;
  }
  delay(10);
  int i = 0;
  while (Serial.available()) {
    serInStr[i] = Serial.read();
    i++;
  }
  serInStr[i] = 0;
  return i;
}

2. twitterからデータを取得する
twitterはStreaming APIが提供されており
リアルタイムにツイートの検索結果を取得できるので、
投稿をトリガーとしてLEDの色変更をリアルタイムに行えます。
参考: Streaming API Documentation

perlでこのAPIを利用するには、
miyagawaさんが作成したAnyEvent::Twitter::Streamが便利です。

APIの仕様書やStreamAPIを理解してなくても、
user_idとpasswordと検索に使いたいfilterの文字列を設定するだけで
お手軽にStreaming APIを利用できます。

[色指定(RGB)] 任意の文字列 ハッシュタグ
形式のツイートが投稿されたとき色を変更したいので
methodをfilterにし、trackにハッシュタグを設定します。
   method   => 'filter',
   track => '#testhoge1',
上記のfilterにマッチする投稿があった場合on_tweetが呼び出されます。
呼び出されたら指定した形式の確認と色指定を
正規表現で確認します。
形式に適合してればusb serial接続されているArduinoに送信します
    $p->write($1) if($tweet->{text} =~ /\[([0-9A-Fa-f]{6})\]/);
[ff0000] blinkm #testhoge1と入力した時は
twitter arduino usb

[00ff00] blinkm green #testhoge1と入力した時は
twitter arduino usb
になりました。
無事に色が変更される事が確認できました。


ソースは以下のようになります。
#!/usr/bin/perl                                                                                                         
use strict;
use Device::SerialPort;
use AnyEvent::Twitter::Stream;

my $done = AnyEvent->condvar;

# Arduino 
my $p = Device::SerialPort->new("/dev/tty.usbserial-A8004JhW");
$p->databits(8);
$p->baudrate(19200);
$p->parity("none");
$p->stopbits(1);
sleep(3); # For Arduino bootup wait.

# Twitter API
my $user = "epic_yoshimax";
my $password = "PASSWORD";
my $keyword = "#testhoge1";

binmode STDOUT, ":utf8";

my $streamer = AnyEvent::Twitter::Stream->new(
   username => $user,
   password => $password,
   method   => 'filter',
   track => $keyword,
    on_tweet => sub {
        my $tweet = shift;
        # [COLOR] #KEYWORD ex) [aa0000] ANY MESSAGE #testhoge1
        $p->write($1) if($tweet->{text} =~ /\[([0-9A-Fa-f]{6})\]/);
        print "$tweet->{user}{screen_name}: $tweet->{text}\n";
    },
    on_error => sub {
        my $error = shift;
        warn "ERROR: $error";
        $done->send;
    },
    on_eof   => sub {
        $done->send;
    },
    );

$done->recv;

参考にさせていただいたサイト
ArduinoとAnyEventを使って,モールス信号でSOS !
Arduino BlinkM I2C通信テスト part1
thingm :: an electronic product studio: BlinkM
perl Device::SerialPortを使ってArduinoに信号を送りBlinkMの色を変更してみる メモ

1. 写真のようにBlinkMをArduinoにつなぎます
IMG_0489


2. macに接続して、デバイスの位置を確認します
mac arduino usb
$  ls /dev/*usbserial*

3. ArduinoでBlinkMの色を変更するプログラムを書きます
BlinkMのサイトからEXAMPLE CODEをダウンロードします。
ここでは、BlinkMのデータシートを読んでI2C通信をwireで実装するのは大変なのですが、
サンプルにあるBlinkM_funcs.hを利用するとその辺の事は何も考えず操作が可能です。
例えば、色を変更したいならアドレスと色番号を指定するだけで色を変更する事が可能です。
BlinkM_getRGBColor( blinkm_addr, &r,&g,&b);
(*BlinkM_funcs.hのラインセンスには注意)
サンプルのBlinkMTesterを参考にして、
RGBの6桁をserialで送信すると色を変更するプログラムを書いてみます。
#include "Wire.h"
#include "BlinkM_funcs.h"

#define BLINKM_ARDUINO_POWERED 1

byte blinkm_addr = 0x00;  
char serInStr[30];

void setup()
{
    if( BLINKM_ARDUINO_POWERED ) {
        BlinkM_beginWithPower();
    } else {
        BlinkM_begin();
    }
 
    Serial.begin(19200);

    // stop seq
    BlinkM_stopScript( blinkm_addr );
    
    // set default color
    BlinkM_setRGB( blinkm_addr, 0xff,0xff,0xff); // white
    
    // fade time
    BlinkM_setFadeSpeed( blinkm_addr, 255);
    
    // change color
    BlinkM_fadeToRGB( blinkm_addr, 0xff,0x00,0x00); //red

}

void loop()
{
	
  int num;
  if( readSerialString() ) {
    //Serial.println(serInStr);
    char* str = serInStr;
    num = atoi(str);
    byte a = toHex( str[0],str[1] );
    byte b = toHex( str[2],str[3] );
    byte c = toHex( str[4],str[5] );
     BlinkM_fadeToRGB( blinkm_addr, a,b,c);
  }
}

#include <ctype.h>
uint8_t toHex(char hi, char lo)
{
  uint8_t b;
  hi = toupper(hi);
  if( isxdigit(hi) ) {
    if( hi > '9' ) hi -= 7;      // software offset for A-F
    hi -= 0x30;                  // subtract ASCII offset
    b = hi<<4;
    lo = toupper(lo);
    if( isxdigit(lo) ) {
      if( lo > '9' ) lo -= 7;  // software offset for A-F
      lo -= 0x30;              // subtract ASCII offset
      b = b + lo;
      return b;
    } // else error
  }  // else error
  return 0;
}

uint8_t readSerialString()
{
  if(!Serial.available()) {
    return 0;
  }
  delay(10);
  int i = 0;
  while (Serial.available()) {
    serInStr[i] = Serial.read();
    i++;
  }
  serInStr[i] = 0;
  return i;
}
スケッチをArduinoに送信してserial monitorで
"ff0000"を送信してテストします
arduino blinkm

4. perlからRGBを指定して色を変えてみます
Device::SerialPortを利用します。
これを使うと以下のような短いコードでシリアル接続が可能です。
#!/usr/bin/perl                                                                                                       
use strict;
use Device::SerialPort;

my $p = Device::SerialPort->new("/dev/tty.usbserial-A8004JhW");
$p->baudrate(19200);
$p->databits(8);
$p->parity("none");
# $p->stopbits(1);
$p->write("ff0000");
色が変わることが確認できました。

参考サイト
ArduinoとAnyEventを使って,モールス信号でSOS !
Arduino BlinkM I2C通信テスト part1
thingm :: an electronic product studio: BlinkM
何分前に投稿などをjavascript側でやるには、
JavaScript Pretty Date が便利です。

以下のように記述すると
<html>
<head>
<title>pretty.js</title>
<script src="../static/jquery-1.3.2.min.js"></script>
<script src="../static/pretty.js"></script>
</head>
<body>
<script type="text/javascript">
  $(document).ready(function() {
    var num = 1;
    window.setInterval(function(){
      var date = new Date();
      $('#container').append(num++*10 + 's : <span class="pretty-time" title="' + date.toUTCString() + '">' + date.toDateString() + '</span><br />');
      $('.pretty-time').prettyDate() }, 1000 * 10);
  });
</script>
<div id="container"></div>
</body>
</html>
titleにある時間が変換されてこのように 1 minutes ago などと表示されます。
setIntervalで10秒毎に、jQueryのセレクターで$('.pretty-time')を選択してprettyDateを実行します。

pretty_js

サンプルはコチラ (10秒後に表示が始まります。)