2015年1月11日日曜日

Play!アプリとBoneScriptの通信 - 2.Playアプリ

もうこの本なしでは行きていけない(Play的に)

というわけで、前回の続きです。

  1. 構成
  2. Playアプリ
  3. BoneScript

■機能■

  1. Webページ
    1. ログイン
    2. グラフ表示
  2. Web API
    1. ユーザ登録 / 更新
    2. データ受信
    3. データ返信
こんだけです。ユーザ登録もAPIで済ませてます…まぁ自分用なので。

■githubリポジトリ■

公開しました。TareObjects/ShowSensorsです。

■ダメなコード■

公開してから気づいたのですが、System.outがそのまま残っていますねぇ…お恥ずかしい。一度必要なところはログに書き換えたのですが、余計なことをしてroll backかけた際に巻き添えになり、また書きなおすのも面倒なのでそのままに。

そのうち直しますm(_ _)m。

Calendarを定義しているところでやたらと
calFrom.set(Calendar.MILLISECOND, 0);
ってのが出てきます。不要なところもあるのですが、ミリ秒単位に初期化されていない値が入ってて一致しない、というバグでしばらく時間を潰してしまったので、それ以来入れてます。まさにあつものに懲りてなますを吹くってやつですねorz

■一応、Playプロジェクトを作るところから■

コマンドラインで
$ activator new ShowSensors
を実行し、プロンプトでplay-javaテンプレートを選択します。できたら
cd ShowSensors
activator run
これでアプリに必要なライブラリなどが自動的にダウンロードされ、ビルドされます。メッセージが落ち着いたらブラウザで http://localhost:9000 を表示するとplay!の画面が表示されます。なお、この画面は、conf/routesの

GET     /            controllers.Application.index()
public static Result index() {
return ok(index.render("Your new application is ready."));
}
及びapp/views/index.scala.html, app/views/main.scala.htmlから生成されています。

■Playプロジェクトにソースを追加する■

Play!は「設定より規約」なので、所定のディレクトリにファイルを作れば、あとは勝手にactivatorが認識してくれます。ただ、vimだけで作業している分にはそれでも問題ないのですが、Eclipseで作業する場合にはコマンドライン側でソースを追加した後、一度Eclipseを終了してから
activator eclipse
でeclipse用の設定を更新し、Eclipseを起動してからプロジェクトを右クリック→Refreshをする必要があります。

また、通常はactivator runしたままで作業を続けられるのですが、build.sbtなどappディレクトリの外にあるプロジェクトの構成に関する部分を修正した場合には、一度activatorを終了してから再起動し、activatorのプロンプト上で
update
eclipse
clean
run
とします。cleanは省略しても良いはずですが、一度ハマったことがあってそれ以来念のため実行するようにしています。

■モデル■

今回、persistentにはEbeanを使います。Springにはいい思い出がないのと、せっかくPlay!がCoCなのにXMLでチマチマやってられっか、ってことでw

モデルはデータベース用とWeb API用が必要です。データベース用はUser.javaとSensorData.java、Web APIとして返すJsonの定義にSensorDataRest.javaです。

いずれも特別なことはしていませんが、SensorData.javaでMany to Oneリレーションシップを定義する際に通常はpublicでインスタンス定義すればそれでOKなはずですが何故かうまく動いてくれず、ググったところ「play!のバグじゃね? アクセサにしたら動いたよ」とのことで、回避できました。

ソース:

それにしても、こんな風にクエリを書けるのは、ホントに楽です。S2JDBCを更に洗練した感じで、今までEOFのEOQualifier最高!と思っていましたが、宗旨替えします。


■ユーザ登録/更新■

Application.javaのnewUser()、フツーです。


■データ受信■

Application.java、receive()。curlをそのままソースに貼っておくと手動テストが楽ですが、こうやってコピペに頼るからいつまで経っても覚えないんですよね…。


■データ返信■

データを返すAPIとして、GET用とPOST用を用意しました。こっちはGET用です。


■認証■

人生で大事なことはタイミングにC調に無責任、と歌ったのは今は亡き植木等師匠ですが、Playでの認証機能に最低限必要なのは、ログインのためのフォームとAuthenticatorの実装、あとは認証の必要なAPIに@Security.Authenticated(Secured.class)アノテーションを付けてやるだけです。

詳細についてはこちら(「認証機能の追加」)…というか、ほぼここからコピペして使ってます。

■データ表示■

Playとしては、Application.javaで単にgraph.scala.htmlを返しているだけです。

で、そのgraph.scala.htmlではD3.jsを使って、PlayアプリのWeb API(上記「データ返信」のところ)からデータを読み込み、グラフを描画しています。以下はデータを読み込んで15分ごとの平均値を求める処理です。平均値なんてサーバ側で求めたほうが良いと思うのですが、動かしてみたら思っていた以上に速かったのでそのままにしていますw なお、念のためですが、これだけでグラフが出るわけでなく、この後に縦軸横軸などの設定が続きます。

■次回は■

いやー、ほんとにサンプルを切り貼りしただけで何にもしていないのですが、でも1つにまとめて動かすのにホント苦労しましたわ。

さて、次はBoneScriptを公開します(しました)。明日の予定です…三連休で良かった。

gist、知りませんでした…

大掃除の成果

今までここにソースを貼るときには、手動でソースを成型して書式を設定してました。貼った後で改行が崩れていたりするとまたそれを治すのが面倒で。

が。gistって便利っすね…何の手間も要らないっすね…。

ということで、途中まで書いてたPlay+Bonescriptの件、現在修正中です。

2015年1月10日土曜日

Play!アプリとBoneScriptの通信 - 1.構成

余分なジャンパが苦闘の痕跡を示すのだった

表題の通り、PIRセンサーの状態をBeaglebone black上のBoneScriptで読み取ってHeroku上のPlayアプリへ送り、D3.jsを使ってグラフ表示する方法をまとめました。

  1. 構成
  2. Playアプリ
  3. BoneScript

■アナログは苦手■

前回の記事の後PIRセンサの調子が悪くなってしまい、対応に追われました。どうもPIRモジュールの温度特性が良くないようで、プルアップ抵抗などを調整してうまく動くようにした後、外出や就寝で暖房がきれると徐々に特性が悪化してしまいます。

今回使っているPIRの最終段はオープンコレクタなのですが…コレクタ側に100Ωの保護抵抗が入っているためlowでも電圧がすっきり落ちてくれません。プルアップで調整するのも面倒になってきたので、これは2SC1815でバッファ入れて解決しました。ベースを10k、コレクタを1kΩで3.3vからプルアップし、エミッタをGND、コレクタからBBBのGPIOにつないでます。



あともう一つ、PIRからのノイズなのか、そのままだとGNDに200mVぐらいのスパイクノイズが乗ってしまってます。これも使い始めたころはなかったのですが、室温が15度を切るようになったから悪化したように思います。なので、4.7μFのケミコンと0.1μのセラコンを入れたところ見違えるように安定しました。

いやはや。

■ハードウェア構成■

センサには秋月の焦電型赤外線センサモジュールを用い、Beaglebone blackの5v電源出力とGNDを接続、上記回路で安定させてからBBBのP8_19に接続しています。非常に単純です。

なお、別のところでも書きましたが、最初は以前秋月で売っていたParallaxのPIR Rev.Aを使ってみたのですが…室内での人の動きと無関係に信号が出ていて、どうやっても改善しなかったので諦めました。現在秋月での扱いが終了しているのは、何か問題があったからではないか?と邪推している今日このごろ。貧乏サラリーマンの数百円を無駄にした恨み、思い知るがいい(違

■まずPlay側■

あっちこっちのサンプルの寄せ集めですが、こんな構成になっています。
controllers---Application.java
              Secured.java
models--------SensorData.java
              SensorDataRest.java
views---------graph.scala.html
              index.scala.html
              login.scala.html
              main.scala.html
Secured.javaなんてファイル名はまさにこのサンプルそのまま、笑ってやってください。

このアプリをHeroku上で稼働させています。データベースには同じくHerokuのPostgreSQLを用いています。どっちも無料枠内。PaaS万歳。

グラフ表示アプリには必要最小限の認証を付けました。でないと「留守・就寝中を世界に向けて発信する」アプリになってしまいますので。

グラフの表示にはD3.jsを使っています。ブラウザ上のD3からPlayアプリのAPIを叩いてJsonで過去24時間分の1分ごとのデータを受け取り、15分単位に集計してグラフを表示します。

■BBB側■

Beaglebone black Rev.Cはほぼ素のママで、BoneScriptを動かしています。0.1秒ごとにサンプリングして1分間のうち何秒間センサが動きを検出したかを集計し、1分ごとにHeroku上へとJSON形式のデータを送っています。

今のところ、送信エラー時のリトライは行っていません。Herokuは24時間に一度勝手にインスタンスがリスタートするので、エラーが出たらバッファにためといて再送するような仕組みを入れておくべきなのですが…。

■次回■

Play!のソースについてご説明します。公開しました。

2015年1月6日火曜日

Energia + MSP430G2でのハマりポイント

そうさ、またデジタル時計さ。MSP430G2553+RTC+秋月巨大LED
小数点のポートはデバッグ用に使用中

■UART関連■

同じG2でも、UARTのTxとRxが逆になっているものがあるので気をつけましょう。2553でもRevision 1.4以前とRevision 1.5は異なります。これはLauchPad基板のジャンパで切り替えるようになっています。

Guide to the MSP430 LaunchPad (MSP-EXP430G2)

シリアルモニタでLaunchPadからSerial.write / printで出力されてくる値を見るにはTxを使うのですが、ジャンパが違っていると書き込みできません。Energiaからの書き込みは正常にできるので、てっきり正しくつながっているものと思い込んでいたら、違いましたorz

■sprintfがクラッシュ■

複雑な書式指定をするとメモリ領域がメチャメチャになってクラッシュします。小さなプログラムだと通っちゃうことが多いのですが、10KBを越えるようなプログラムで、例えば、
sprintf(buf, "%02d%02d%03d%d", h, m, t1, t2);
とやると、以下のような症状が出たりします。

  • bufに値が入らない
  • 数秒ごとに繰り返しsetupが呼び出される
  • シリアルポートが文字列の途中でぶっちぎれる
  • 一度電源引っこ抜かないとEnergiaから書き込めなくなる


解決策としては、バッファとして使うメモリにvolatile指定を行い、sprintfの書式、特に数値変換については極力単純にして、あとは(上の行と同等のことをするには):
volatile char buf[16],temp1[16], temp2[16];
sprintf((char *)temp1, "%d", 10000 + h*100 + m);
sprintf((char *)temp2, "%d", 10000 + t1*10+t2);
sprintf((char *)buf, "%s%s", (char *)temp1+1, (char *)temp2+1);
で1つにまとめます。temp1,temp2を+1しているのは最初の'1'をスキップさせる古いc言語のテクニックです(懐かしい…)。

■MSP430G2553について■

これ温度センサー内蔵なんですね。analogRead(TEMPSENSOR)使うと華氏*10で返ってくるので、楽です。ワンチップで温度計作れます。我が家の他の温度計とも誤差1度以内なので、まぁ合っているんだろうなぁ、みたいなw

で、巨大LEDですが…3.3v駆動+PWMで制御しているのをいいことに、電流制限抵抗なしでつないでます。良い子は真似してはいけません。

さて、あとはRTCとの接続か…。

一応Xtalを外付けしてオープンソースのライブラリをつかえばリアルタイムクロックとしても動くのですが、年月日まで管理してくれないのでその辺を自前で実装するのが面倒くさい。かといって、RTCについても以前RTC-8564NBをArduinoにつないだときのソースを探すのが面倒くさい。

昨日今日とsprintfで全能力を使い果たしてしまったので、まぁそのうち元気が出たら作ります。

私を何より元気にするのは現金なんすけどねw

■追記■
これをデジタル時計として動くようにしました。ソース公開してます。予定ではRTCチップを外付けする予定でしたが、水晶発信しだけ外付けして使いました。

2015年1月5日月曜日

LEDアレイを波打たたせた



上の動画、音量注意っす。調節する方法がわからんw

各色LEDが一列に並んだモジュールを電子工作仲間のOさんから頂戴しました。どうもありがとうございます。

LEDとデジタル時計が三度の飯より好きな私なので、さっそくLチカしてみました。ただ、普通に点滅させても面白くないので、ウェーブしてみます。でもウェーブさせるにはPWMが必要ですが、いただいたのは12bit分、Arduino unoのPWMは6chしかありません。

ので、ソフト的に処理しました。一番内側のループphaseの値を0〜31まで変化させ、sinテーブルの値がその値よりも大きければ点灯、小さければ消灯させます。sinテーブルから拾ってくる位置をピンごと(i*3)に、また時間の経過(offset)ごとにずらしていけば、こんな具合いにうねうね動きます。モジュールの端にGND端子があり、1枚はArduino unoの13ピン隣にあるGNDに、もう1枚のGNDは7ピンに接続してLOWを出力しています。

だいたいPWMとしての基本クロックは70hzぐらい、肉眼で見ている分にはあまりフリッカは感じないですが、目をすっと動かすと点滅が軌跡となって見えますねぇ。


以下ソースです。
const int p01 = 13;
const int p02 = 12;
const int p03 = 11;
const int p04 = 10;
const int p05 =  9;
const int p06 =  8;
const int p07 =  6;
const int p08 =  5;
const int p09 =  4;
const int p10 =  3;
const int p11 =  2;
const int p12 =  1;
 
const int pGnd = 7; 
const int pins[] = {p01, p02, p03, p04, p05, p06, p07, p08, p09, p10, p11, p12};
const int nPins = sizeof(pins) / sizeof(int);
const int nSin = 32;
 
int iSin[nSin]; 
void setup() {
  pinMode(pGnd, OUTPUT);
  digitalWrite(pGnd, LOW);

  for (int i = 0; i < nPins; i++) {
    pinMode(pins[i], OUTPUT);
    digitalWrite(pins[i], LOW);
  }

  int half = nSin / 2;
  for (int i = 0; i< nSin; i++) {
    float d = (float)i / (float)nSin * 2.0 * 3.14159265;
    iSin[i] = sin(d) * half + half + 2;
  }
}

int phase = 0;
int outer = 0;
int offset = 0;

void loop() {

  for (int i = 0; i < nPins; i++) {
    int output = iSin[(i*3 + offset) % nSin] /2;
    int lowHigh = (output > phase) ? 1 : 0;
    digitalWrite(pins[i], lowHigh);
  }

  phase++;
  if (phase >= nSin) {
    phase = 0;
 
    outer++;
    if (outer > 2) {
      outer = 0;
   
      offset++;
      if (offset >= nSin) {
        offset = 0;
      }
    }
  }
}

2015年1月4日日曜日

PlayとD3とBeaglebone



会社でのお仕事として年明けからPlay+Spring+Emberを使ってサイトを1つ立ち上げることになっているのですが、どれもチュートリアルをなぞった程度で本格的に使ったことありません。しかし:

  • 休み中はしっかり休みたい。
  • でも勉強しておかないと死ぬのは確実。
  • でも休み中は電子工作方面に浸りきりたい

ので、この3つを満たすために「Beagleboneで収集したデータをPlay! frameworkで書いたHeroku鯖へ送り、グラフ化して表示」ってやつを作ろうと思います。visualizeには同僚さんに教えてもらったD3jsというフレームワークのグラフがあまりにもきれいなので、それ使います。EmberとSpringのことはとりあえず忘れます。

■動作フロー■

基本的にこんな動き。まずセンサ〜収集系:
  1. Beaglebone Black Rev.c上でPIRセンサーを読み取り人の動きを検出
  2. 検出した結果は1分あたり動いた秒数として出力し、Heroku鯖へ送る
  3. Heroku上で動くアプリはWeb APIとしてデータを受信する。
  4. 受信したデータはHerokuのPostgreSQL上にリングバッファ的に保存(Herokuのポスグレは10k行まで無料で使えるので)。
続いてデータ表示系:
  1. ブラウザからのリクエストを受けてHTMLを返す
  2. HTML上でD3.jsがHerokuへデータをリクエスト、Jsonで返す
  3. D3.jsがグラフを描画
D3.jsはデータ形式も多彩でcsv, tsv, json, xmlなど思いつくものはだいたい入ってます。

■予備実験■

BBB+PIRセンサーは現在絶賛安定稼働中なので、未体験要素としてD3jsでのグラフ生成を試してみます。棒グラフを出すだけならChart.jsの方が圧倒的に簡単なのですが、もうね、表現力が圧倒的すぎるのですよD3様は(そこまで使いこなせるかどうかは別の話)。

ということで、まずチュートリアルからサンプルソースをコピペ。こんな立派なグラフがこれだけで?と思うぐらいソース短い。

■Play 2.3.7■

しばらく自宅MacでPlayをいじっていなかったら、ターミナルでactivatorとタイプしてもエラーになってしまう。のでbrewでアンインストール&インストール(安易だ)。
brew uninstall typesafe-activator
brew install typesafe-activator
で、プロジェクトを作る:
activator new ShowSensors
起動後、play-java templateを選択。戻ってきたらactivator uiを起動
cd ShowSensors
activator ui
しばらくしてブラウザ上にIDEが開く。最近ブラウザIDEが流行ってますねぇ。ただ、エディタがタブ対応でないならviの方がマシだし、何よりcompile/runがうまくいかないので今回も利用を見合わせます。Play2の場合、Eclipseを使うメリットがあんまり感じられないのでsublime text2使います。ctrl+cで終了し、
activator run
ビルドその他のメッセージがおとなしくなったところでブラウザで localhost:9000 を開けばいつものページ、緑色の「Your new application is ready」のメッセージがお出迎えしてくれます。

■ヘンなエラー■

ひと通り実装をしたところで試すとこんなエラーが:

[error] play - Cannot invoke the action, eventually got an error: java.lang.RuntimeException: Error getting BeanDescriptor for path User from models.User
ググってもどうもピンと来ない。何となくEbean系の間違いのようなので、
  • とりあえず@OneToMany / @ManyToOneなどを消して見る
  • とりあえずactivator clean / activator updateなどを試す

などやってみたのですが、ダメ。その後、トレースしてみると、
User user = find.fetch("user").where() .eq("email", inEmail) .findUnique();
ここで落ちてました。そりゃそうだ。ここを
User user = User.fetch().where() .eq("email", inEmail) .findUnique();
に変えたら通りました。先にUserの生成と検索についてのtestを書いてりゃ容易に切り分けが出来ていたケースですね…反省(@元日)。

■で、Web API■

フツーにRoutesにURIとコントローラを書いて、
GET /fetchFromHours controllers.Application.fetchFromHoursGet()
コントローラでdbからデータをfetchし(仮にarrayDataとする)、最後に return ok(Json.toJson(arrayData)); と書けばOKです。以下は過去24時間の計測データを返すAPIの処理:
// curl --header "Content-type: application/json" --request GET http://localhost:9000/fetchFromHours
public static Result fetchFromHoursGet(String inEmail) {
User owner = User.findByEmail(inEmail);
Calendar calFrom = Calendar.getInstance();
calFrom.setTime(new Date());
calFrom.add(Calendar.HOUR_OF_DAY, -24);
calFrom.set(Calendar.MILLISECOND, 0);
Integer hours = 24;
List<SensorData> sds = SensorData
                       .findByUserSinceDateForHours(owner, calFrom, hours);
if (sds == null || sds.size() == 0) {
return badRequest("no data found");
}
List<SensorDataRest> sdr = new ArrayList<SensorDataRest>();
for (SensorData sd : sds) {
sdr.add(new SensorDataRest(sd));
}
return ok(Json.toJson(sdr));
}

■Macにポスグレをインストールして起動■

brew install postgresql
initdb /usr/local/var/postgres -E utf8
postgres -D /usr/local/var/postgres &
これで
psql -l
とやってデータベース一覧(初期状態の設定テーブルが2-3個あるはず)が見えればOK

■Web APIでURLパラメータを渡すには■

今回は使いませんでしたが、http://.........../apiName?name=kura&email=foo@bar.comという処理をしたい場合には、routesに
GET /apiName  controllers.Application.api(name:String, email:String)
と書き、ソースに
public static Results api(String inName, String inEmail) {
....
}
と書けばOKです。routesにはパラメータが省略された時の値を指定することも可能で
GET /apiName controllers.Application.api(name:String ?="kura", email:String ?="tare@panda.com")
と書きます。RESTfulな書き方については簡単に見つかるんですが?と&でパラメータを渡す方法がなかなか見つからなかったのでメモしておきます。

■Heroku上のpostgreSQLへ接続■

まずHeroku上のpostgreSQLを有効にします。

すると、URLやid, passwordなどが通知されますので、それに基づいてapplication.confを書き換えてdatabaseをH2からpostgreSQLに変更し

build.sbtにpostgreSQLのドライバを追加します。
libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  javaWs,
  "com.fasterxml.jackson.core" % "jackson-databind" % "2.4.4",
  "com.fasterxml.jackson.core" % "jackson-annotations" % "2.4.4"
,
  "postgresql" % "postgresql" % "9.1-901-1.jdbc4"

)
ま、上の設定が決まるまで一発では動いてはくれなかったんですが…その辺は末尾の「ハマりリスト」をご笑覧くださいorz

■Herokuへdeploy■

これはもうここに書いてあるそのまんまです。
  Heroku へのデプロイ(playframework.com)
便利になったものです…初回はdependencyのチェックでエラい時間かかるけど、待ってりゃ終わります。終わったところで

で、以下の様な表示が出ればOK
koichi$ heroku ps
=== web (1X): `target/universal/stage/bin/showsensors -Dhttp.port=$PORT`
web.1:
up 2015/01/04 08:36:10 (~ 2s ago)

大事なのはここのupってところ。これがcrushedだとデプロイor起動に失敗したということ。もう見飽きるほど見ましたよ…ええ…。

■BoneScript変更■

テストではcsvに書き出すだけでしたが、コードを追加しました。まずpayloadを作って
var body = JSON.stringify({
    date:  sDate,
    count: sCount,
    email: "kkurahashi@me.com"
});
POSTします。
var request = new http.ClientRequest({
    hostname: "ホスト名",
    port: 80,
    path: "/receive",
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Content-Length": Buffer.byteLength(body)
    }
});
request.write(body);
request.end();
通常のPlayアプリだとポートは9000ですが、Herokuにデプロイすると特に設定しなくても80でつながります。他にエラー処理もあるけど、あとでGithubに上げるのでそっちをご覧くださいませ。

■できあがり■

8:48はトイレに行ってた

■今後■

上記は生データ表示なので24時間収集すると表示が細かすぎます。これを5分か15分にサマライズします。あとはローカルとリモートのPostgresをdev/deployで自動的に切り替わるような設定も組み込まないといけません。ぽすぐれと接続できないでウロウロしてた時にその辺の設定は全部後回しにしてしまい、現状はapplication.confを手動で切り替えておりますw

それからソースを掃除してからGithubでプロジェクトを公開します。まぁ今度の週末にでも。

そして以下は今回の作業でハマった箇所です。改めて見直すと…我ながら…アホです。でも失敗して覚える…というか失敗しないと学習しないタイプなので、とっても勉強になりました。正月休みはウォーキングにも行かないでこればっかりやってたせいで3kg太ってけども。

餅は危険です。

■ハマりリスト■

  • テストが作動しない
    • せっかくテストコードを書いたのに activator test を実行しても新しいテストコードが認識されないことがある。そういう場合には、activator cleanを実行すると直る。もしダメなら一度activatorからexitして(もし起動していれば)Eclipseを終了させ、activator cleanを実行してから再度activatorに戻ってtestを試してみる。
    • 全般的にソースを追加した場合にはcleanするかactivatorを一度終了した方がいいかもしれない。また、application.confやsbt関連ファイルを弄った場合にはactivatorを終了/再起動しないとダメっぽい。
    • あと、activatorを起動しっぱなしで半日作業したら「メモリが足りない」ってエラーが出たことがありました。Eclipseばかりではなく、たまにはコンソールも見ましょう。
  • @Constraints.Requiredが機能しない
    • Ebeanでは @NotNull を使うorz
  • @ManyToOne(fetch=FetchType.EAGER)が効かない
    • objをfetchしてきた時、obj.toOneには値が入っているけどobj.toOne.someとやるとnullになってしまう。toOneをprivateに変更し、getter/setterを設けることで解決。
    • StackOverflowには「Play!のバグじゃね?」って意見もあるけど、どーなんでしょうね。
  • 複数項目を対象にしたunique属性
    • @Entityの後に @Table(uniqueConstraints = @UniqueConstraint(name="制約につける名前", columnNames = { "attr1", "attr2" })) ...とカラム名を列挙する。
    • なお、java上のattribute名ではなくdb上のカラム名なので、対象となるattributeには@Columnでカラム名を指定するか、Evolution表示で出てくるカラム名を使うこと。
  • PostgreSQLと接続できない
    • application.confでのURI書式が違ってたorz
      db.default.driver=org.postgresql.Driver
      db.default.url="jdbc:postgresql://localhost:5432/データベース名"
      db.default.user=ユーザ名
      db.default.password=パスワード
  • PostgreSQLでテーブルができない
    • userというテーブル名は予約語なので作れませんorz
    • クラス名を変更するか、@Table(name="users")を追加してテーブル名を変更する。
  • その後、UserをUsersに変更したけど、evolutionで生成されるSQLが古いままでcleanなどをやってもcreate userのまま
    • 中途半端なところでevolutionが止まったため、管理テーブルplay_evolutionsだけがpostgreSQL上に出来ていたのが原因っぽい。
    • ので、drop databaseでまるごと削除したら動いた。
  • 以下、Herokuへデプロイできた後の話
  • コンソールやpsqlで見るとデータがあるのにAPIでfetchできない
    • Herokuがアメリカ時間だったため。以下の記事を参考にして、JSTに変更したら治った。インスタンスの再起動も不要でした。
    • http://blog.ruedap.com/2011/02/10/heroku-timezone-japan-jst
    • コマンドラインで heroku config:add TZ=Asia/Tokyo

2014年12月31日水曜日

「勉強のあかり」のLEDスタンド

8x8 スペクトルアナライザw

節電でシーリングライトを電球形蛍光灯一個に交換して生きてきましたが、どうにも手元が暗いのでパナソニックの「勉強のあかり」仕様LEDスタンドを買ってみました。スタンドの土台がデカいと邪魔なのでクランプ式、発光部分が小さいと影ができやすいので大きいのを選んだのですが…組み立ててみたら想像以上にデカかったw クランプと本体は分離できるので、先にクランプを机に取り付けるだけ。昔使ってたクランプ式は一体型で重心が上にあったので苦労したっけなぁ…。





このところ本が読みにくいし頭に入らなくて、まぁ老眼だし脳ミソもダメだからしょうがないなと思っていたのですが…このLEDスタンドだとやたら読みやすい。今までページ上のコントラストが低くて文字認識で精一杯だったのが、読みやすくなったことで学習とか記憶に脳ミソを回せるようになったのでせうかw

もちろんハンダ付け作業も楽。発光部分が横に長く拡散板を使っているので、いわゆる多重影ができないし、演色性も高いので透明ブレッドボードとスズメッキ線が見分けにくいとか、溶けたハンダがキラっと光る瞬間を見逃すこともない。

と、読書用作業用でも十分満足してたんですが、写真も何だかスッキリ写ります。やっぱ演色性って大事だな…としみじみ思う。

まぁ…Macの汚れもくっきり写っちゃっているんですけどね…。

2014年12月29日月曜日

Play javaでjson-simpleを使う

休み中にずっしり伸し掛かる課題

今お勉強を兼ねて、趣味でHeroku+Play+D3.jsでアプリを書いているのですが、プロジェクトにjson-simpleを組み込めなくてハマりました。

最初にplugins.sbtに
    addSbtPlugin("com.googlecode.json-simple" % "json-simple" % "1.1.1")
を追加して not found。次に同じくplugins.sbtの上記行の前に
    resolvers += "maven repository" at "http://central.maven.org/maven2/"
を追加してもダメ。URLを色々変えてもダメ。

一晩寝て、間違いに気がついた。plugins.sbtじゃなくてbuild.sbtのLibraryDependenciesに追加してみたら、ようやく動きました。

ちゃんと寝ないとダメよねorz

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  javaWs,
  "com.googlecode.json-simple" % "json-simple" % "1.1.1"
)

さて、あと2日出社して冬休みだ(1月6日まで…ジャンケンで負けて後半組)。

2014年12月5日金曜日

Play! Framework 2.0 -> 2.3

というわけで、担当プロジェクトはPlay! Framework 2.3(Java)を使うことに決まりました。どうせならScalaの方が良かったんですが、「社内リソースがない」ということで。そりゃそうだ。

で、自分の知識をScala->Javaに切り替えなければならないので、適当な記事を参考にひと通り学習しなおして見ることに。いやー…びっくりするほど忘れてた…。

記事はコレ。Play 2.0ベースで書かれています。手元の最新は2.3.4、1.2->2.0ほどではないものの、かなりの変更があって大変でした。連載開始2012年4月か…途中長い中断があって、待ち遠しかったのを覚えてます。


■EBean関連で右往左往■

ま、一言でいえば、コレです。中の人が「EBeanは開発止まってるから、やっぱ2.3からJPAに戻るわw」と言ったとか。

しかし記事はEBean前提だし、とりあえず「EBeanかJPAか」を自分なりに評価しないといかんので、とりあえずPlay 2.3でEBeanを使ってみることにしました。

で、最初から記事にそってサンプルを動かしていくと、まず連載第1回の2/3で止まります。コマンドがplayからactivatorに変わったからです。playとタイプする代わりにactivatorとタイプし、メニューで表示されるテンプレートで「5) play-java」を選びます。


次のハマりポイントは連載第2回の1/3、Parent.java。念のため、ものすごく蛇足ですが、app/modelsというフォルダを自分で作り、その下にParent.javaを作る必要があります。

で、Parent.javaを保存して実行するとcom.avaje.ebean.validationがないというエラーが出ます。で、「com.avaje.ebean.validation not found」なんてキーワードでググると、
ってのがヒットします。でも

  1. project/Build.scalaではなくplugins.sbtに変わっている
  2. plugins.sbtに追加しても変わらない→activator runをやり直さないと反映されない
  3. 「"org.avaje.ebeanorm" % "avaje-ebeanorm-api" % "3.1.1"」を追加してactivator runするとエラー

です。結果からいえば、エラーの出る
    import com.avaje.ebean.validation.NotNull;
をコメントアウトして、替わりに
    import play.data.validation.*;
とします。さらに、@NotNullアノテーションを@Constraints.Requiredにします。これで先に進めます。


そして(2/3)でChild.javaを作りParent.javaを修正しますが、Child.javaでは例によって
    //  import com.avaje.ebean.validation.NotNull;
をコメントアウトして
    import play.data.validation.*;
に変更し、Parent.javaには
    import java.util.List;

    import java.util.ArrayList;
    import javax.persistence.CascadeType;
    import javax.persistence.OneToMany;
を追加する必要があります(上2行はEBeanとは関係ないですが)。これでブラウザをリフレッシュするとコンパイルエラーはなくなるはずですが、実行時エラーが出ます。


これは正常です…まだApplication.javaを書き換えていないので。(3/3)の指示にしたがってapp/controllers/Application.javaを書き換え、ブラウザをリフレッシュすると:


はい、出来上がりです。ここまでをPlay 2.0で試した時は確か小一時間ぐらいだったと思うんですが、今回は試行錯誤の山に阻まれて半日潰れました。いやはや。

この後PostgreSQLへの対応についての記述がありますが、そこだけ飛ばして連載の最後まで試しましたが、特に問題はなかったはずです。

■フレームワークを修得する場合■

なお、頭いいヒトはそんなことしなくても覚えられると思うのですが…私は本気でフレームワークを覚えるときには、記事を見なくてもチュートリアルと同じものが作れるようになるまでを第一段階としています。さすがにサンプルデータまでは再現しないですが、記事を見ないでうろ覚えで試している段階では当然ミスをします。ミスを修正するためには原因を調べなくてはならず、これが基本的な操作を修得する上で大変役に立ちます。

記事にはミスった時の対応まで書いてないことが多い(というよりも一度最後までサンプルプロジェクトを作ってうまくいくことを確認し、記事を書きながら再度新しく作ったりします)のですが、実際に使うようになって一番困るのはソコですし、どうしても分からない場合には記事を辿っていけるので「こういう現象が出た時の原因は、コレ」というのが比較的短期間で身につけられます。実際の開発で使うような大きなプロジェクトで環境設定に起因するエラーが出るとホント突き止めるのが大変ですからねぇ。

で、基本的な操作が身についていると、その後はAPIを虱潰しに調べていく際などにも推測が効くようになります。

これに気づいたのは、WebObjectsのセミナーで何度も「Movies」というサンプルを作った経験からです。自分はさすがにミスをしないのですが、受講生のみなさんのミスを潰しているうちに、自然にトラブルシューティングが身につきます。

当時は「朝のウォームアップ」と称して、さすがに毎日ではないですが、朝一で「Movies」を作っていました。当時は意識していませんでしたが、これが私にとってはGTDでいうところの「朝一に消化できるタスクを用意する」ことだったのかな、と思ったり。

まぁ、それに気づいたので、最近朝一に簡単なタスクを片付けるようにしてウォームアップしてます。

もっとも、それでせっかく上がった調子も、朝礼が長いとしぼみきってしまうんですけどね…ホント、何とかならんかな…。他の部署の連絡事項を聞いている時間があったら、スクラムミーティングの方が良いと思うの。

2014年12月3日水曜日

赤外線LED/受光素子発見@部品沼

他に電解コンデンサ,CDS,タクトスイッチ

Arduinoとセットになったパーツセットに入っていたはずで、部品沼のどこかに沈んでいるのは間違いない。

ちょっと時間ができたので本気で探したら…プリント基板箱の底に沈んでいました。まぁ買っても数百円なんだけど、使ってあげないと可哀相だし(その発想がすでに廃人)。

これで今週末はBBB+Lircで遊べる。