Pebbleでサッカースコアライブ更新表示してみた
Pebble Smartwatch | Smartwatch for iPhone & AndroidとSimply.jsででなんかできないかなぁと考えてみた。
わたし、サッカーをよく見るのですが、今開催されている試合の結果がリアルタイムで分かったら何か楽しそうなので、作ってみることにしました。
ワールドカップを来月開催されることだし。
まず、サッカースコアのライブ更新しているサイトを探すと以下が良さそう。
LiveScore Soccer : Live Soccer Scores by LiveScore.com
欧州リーグだけでなくJ1,J2,J3(!)もカバーしている。
もちろんワールドカップも。
このサイトから情報を取得するためのスクレイピングは、Javascriptに不慣れなのと、一度使って見たかった簡単にスクレイピングしてWebAPI化してくれるという
kimono : Turn websites into structured APIs from your browser in seconds
を使ってみたかったので、これでいく。
15分くらいで直感的にWebAPIができました。
以下がそのWebAPIで取得できるJ1の試合結果のJSONファイル。
https://www.kimonolabs.com/api/52h5eq42?apikey=664315ac6dd2128d90351faeb721fb63
また、Simply.jsの使い方は
ひとりぶろぐ » 2.0で面白くなったスマートウォッチPebbleを、JavaScriptゴリゴリでネット監視装置として使う
を参考にさせてもらいました。
あと、開発はCloudPebbleを利用してブラウザ上で実施。
ソースはこんな感じ。
ごちゃごちゃ書いてあるけど、やっていることは
#試し試しやっててかなり汚いです
#あと、タイムゾーンがあってないです
var api_uri = 'http://www.kimonolabs.com/api/52h5eq42?apikey=664315ac6dd2128d90351faeb721fb63'; var match_text = ''; //simply.title('J1 League'); //simply.style('small'); simply.scrollable(true); //simply.on('singleClick', function(e) { function refresh(opt) { if( opt.length > 0 ) { var league = opt.match(/kimpath2=(.*)&kimpath3=(.*)/); console.log('league[0]=' + league[0]); console.log('league[1]=' + league[1]); console.log('league[2]=' + league[2]); if( league.length == 3 ) { opt = '&kimpath2=' + league[1] + '&kimpath3=' + league[2]; } else { opt = ''; } } else { opt = ''; } api_uri_opt = api_uri + opt; ajax({ url: api_uri_opt, type: 'json' }, function(data) { var matches = data.results.collection1; var match_days = data.results.collection2; if( league.length == 3 ) { match_text += league[1] + '/' + league[2] + '\n'; } for(var i=0; i < match_days.length; i++) { match_text += match_days[i].match_day + ','; } match_text += '\n'; for(var i=0; i < matches.length; i++ ) { if( matches[i].score == "? - ?" ) { // not live score = ' ' + matches[i].score + ' '; } else { // live score = ' ' + matches[i].score.text + ' '; } match_text += matches[i].match_time + ': ' + matches[i].home_team_name + score + matches[i].away_team_name + '\n\n'; } simply.text({ body : match_text }); match_status = window.localStorage.getItem('match_status'); if( match_status != match_text ) { simply.vibe(); } window.localStorage.setItem('match_status', match_text); }); } simply.begin = function() { try{ var options = window.localStorage.getItem('options').split('/'); if( options.length > 0 ) { for(var i=0; i < options.length - 1; i++) { console.log('opt is = ' + options[i]); refresh(options[i]); } setInterval(refresh, 60000); } }catch(e){ concole.log(e); } }; // https://github.com/pebble-hacks/js-configure-demo/blob/master/src/js/pebble-js-app.js Pebble.addEventListener("showConfiguration", function(e) { console.log("showConfiguration!"); Pebble.openURL('https://dl.dropboxusercontent.com/u/9794530/pebble_soccer_live/config.html'); } ); Pebble.addEventListener("webviewclosed", function(e) { console.log("configuration closed"); // webview closed var options = JSON.parse(decodeURIComponent(e.response)); var opt_str = ''; console.log("Options = " + JSON.stringify(options)); for(var key in options) { if( options[key] == true ) { var path_list = key.split('/'); console.log('&kimpath2=' + path_list[1] + '&kimpath3=' + path_list[2] + '\n'); opt_str += '&kimpath2=' + path_list[1] + '&kimpath3=' + path_list[2] + '/'; } } window.localStorage.setItem('options', opt_str); });
で、Pebbleで表示はできたんだけど1つ問題が。
1分毎にスコアを更新したいのだけど、下記記事によると
Pebble Javascript Tips And Tricks
setInterval(refresh, 60000);
はあまりよくないらしい。
でも、上の記事にあることをやろうとすると、Simply.jsでは力不足で、
WatchAppをCで、SmartPhone側のアプリをJavascriptで書く必要があるみたい。
う~ん。
Raspberry Pi で監視カメラ
Raspberry PiにUSBのWebCameraをつけて室内の監視カメラにしてみました。
WebCameraはこれ
LOGICOOL ウェブカム HD画質 120万画素 C270
- 出版社/メーカー: ロジクール
- 発売日: 2010/08/20
- メディア: Personal Computers
- 購入: 21人 クリック: 267回
- この商品を含むブログ (20件) を見る
アプリは motion.
sudo apt-get install motion
使い方はここを参考に設定しました。
Linux + motion + webcamでライブ監視カメラを設置する
設定ファイルは /etc/motion/motion.conf。
変更した設定はこのあたり。
#この記事を書くために見直していたらtimelapse撮影/動画生成もあるみたい
# 静止画(JPEG)はbest shotのみ保存。 output_normal best # 別PCからWebCamera映像を見れるように webcam_localhost off # 制御は別PCからできるけどuser/passwordで制限をつける control_localhost off control_authentication user_name:password
これで
http://192.168.0.2:8081/ とかでWebCameraの映像が見れるようになります。
ただ、監視カメラの目的が自分が不在時の部屋の監視なので、自分が家にいるときは撮影しなくていい。
また、そのうちドメインを取って外部から見れるようにしたいので、なおさら自分が部屋にいるときは撮る必要がない。
# セキュリティ的な見直しは必要だけれども
そこで、「自分が部屋にいるか判定」にスマホのBlueTooth接続の有無で判断するにした。
部屋にいるときは、motion を stop、いないときは motion を start させる。
まず、BlueToothアダプタはこれを購入。
PLANEX Bluetooth USBアダプター Ver.4.0+EDR/LE(省エネ設計)対応 BT-Micro4
- 出版社/メーカー: プラネックス
- 発売日: 2012/02/10
- メディア: Personal Computers
- 購入: 3人 クリック: 9回
- この商品を含むブログを見る
インストールとスマホとのペアリングは、ここを参照して実施。特に問題なく完了。
Raspberry PiでBluetoothを扱う - Programming Log
自分で仕組みを作る前にぐぐってみると、デスクトップをオフ(スクリンセーバーモードに移行?)できるアプリはあった。ただ、今回の目的には使えなさそう。
第267回 Bluetoothデバイスで離席管理する:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社
「自分が部屋にいるか判定」にスマホのBlueTooth接続の有無で判断する
のにどうすれば一番いいかよくわからないけど、
力技で l2ping でスマホのBlueToothから応答があれば、部屋にいると判定して motion のプロセスを止めることにした。こんな感じ。これをrootのcronで適当な間隔で回す。
#!/bin/bash # 実際はスマホのbluetoothアドレスを設定 bt_addr='XX:XX:XX:XX:XX:XX' resp_bt=`l2ping ${bt_addr} -c 1|grep ' 0% loss'` if [ ${#resp_bt} != 0 ]; then echo "bt remote device exist." service motion stop else echo "bt remote device doesn't exist." resp_motion=`ps auxww|grep '^motion.*/usr/bin/motion'` # echo ${#resp_motion} if [ ${#resp_motion} = 0 ]; then echo "motion isn't running." service motion start else echo "motion is aleady running." fi fi
# もっとスマートに書けると思うのだが...
2014/02/01 追記
- if-else文の中身が逆になってた(orz)のを直しました。すいません。
- /var/run/motion/motion.pid ファイルが存在している場合は、motion が起動していると判断する方がセオリーぽい。
2014/04/29 追記
- l2pingだとなぜか反応がないことがあるのでhcitool nameに変更。自分の環境ではこっちの方が安定動作しています。
- motionの起動チェックは、/var/run/motion/motion.pidの存在チェックに変更
#!/bin/bash # 実際はスマホのbluetoothアドレスを設定 bt_addr='XX:XX:XX:XX:XX:XX' #resp_bt=`l2ping ${bt_addr} -c 1|grep ' 0% loss'` resp_bt=`hcitool name ${bt_addr}` #echo ${#resp_bt} if [ ${#resp_bt} != 0 ]; then echo "bt remote device exist." service motion stop else echo "bt remote device doesn't exist." # resp_motion=`ps auxww|grep '^motion.*/usr/bin/motion'` # echo ${#resp_motion} if [ -e /var/run/motion/motion.pid ]; then echo "motion is aleady running." else echo "motion isn't running now." service motion start fi fi
Pebble WatchFace開発
年末にPebble WatchFaceを作ってみたので、その備忘録。
- Pebbleとは?
詳細はこの辺を見て。
公式: Pebble Smartwatch | Smartwatch for iPhone & Android
まとめ: スマートウォッチ「Pebble」まとめ - NAVER まとめ
分解: Pebble Teardown - iFixit
いろんなWatchFace: http://www.mypebblefaces.com/
ここから開発について。
開発関連情報
とにかくここ、こまったらここを見る。
Develop for Pebble
開発環境
自分のPCに環境を作ってもいいですが、Web上でコーディング&コンパイル&スマホへのインストールまでできるサイトがあったので、今回はCloudPebbleで開発します。
ちなみにWindowsは今のところ非対応らしい。ただ、Windowsで開発するにせよ、CloudPebbleで開発するにせよ、SDKのアーカイブにサンプルコードが含まれているので、ダウンロードしておいた方が幸せになれます。
WatchFace?WatchApp?
WatchFaceはPebbleのボタンを使わないもの、WatchAppはボタンを使えるもの。
BlueTooth通信の有無ではないらしい。
サンプルWatchFace
今回、作ったのは砂時計。ざっくりとした仕様は
- 1時間で砂が流れ切る
- 上側と下側の砂の量は、時間と対応付けて表示を変える
- 砂が流れるアニメーションをつける
- 砂が流れ切ったら砂時計が1回転する
- Pebbleを振ると下側の砂が平らになる
// アプリの開始時に実行 static void do_init(void) { //割り込みハンドラの登録、リソースの確保、初期化とか } // アプリの終了時に実行 static void do_deinit(void) { //リソースの開放とか } int main(void) { do_init(); app_event_loop(); // おまじない do_deinit(); }
…詳細を書こうと思ったけど、
Develop for Pebbleの'Getting Started', 'Pebble Developer Guide'と拙作のソースを見てもらった方が早いなぁ、と思ったり。
きたないけどソースはzinziroge/sandglass_watchface · GitHubに置いてあります。
他にもGithubやhttp:// http://www.mypebblefaces.com/でソースが公開されているものもあるのでそれを参考にするのが手っ取り早いと思います。
これで終わるのもあれなのではまったところだけ箇条書き。
時間割り込みの登録
秒、分、時、日、月、年が変わるタイミングで呼ばれるハンドラが登録できるのだが、例えば1秒毎、1時間毎に割り込みをかけようとして以下のように2つハンドラを登録したら1秒毎の割り込みが実施されず。
tick_timer_service_subscribe(SECOND_UNIT, &handle_second_tick); tick_timer_service_subscribe(HOUR_UNIT, &handle_hour_tick);
正解は、これ。
tick_timer_service_subscribe(SECOND_UNIT|HOUR_UNIT, &handle_tick_timer);
で、ハンドラ側で割り込み要因を判別して処理を分ける。
void handle_tick_timer(struct tm *tick_time, TimeUnits units_changed) { if( units_changes | SECOND_UNIT) { // 1秒毎に実施する処理 } if( units_changes | HOUR_UNIT ) // 1時間毎に実施する処理 } }
2pixel以上の太い線が描けない
graphics_draw_line() という線を引くAPIがあるが、太さを指定できない(つまり1pixel)。
水平線や垂直線なら graphics_fill_rect() で実現できる。でも、斜め線が描けない。
PebbleにはDrawing Pathsという一筆書きで線を描いて、内部を塗りつぶすこともできるデータ型がある。
これを使って太さと傾きに応じて太線の4頂点の座標を計算すれば、gpath_draw_filled()で描ける。
ちなみにsin,cos,atan2はテーブルで持っていてそれをAPIで参照できるので、上の座標計算もダイナミックにできます。
1つ作ってみての感想
WatchFaceぐらいの規模だと環境作る方がめんどいから、クラウドで開発できるのすごくいいと思う。
エディタもメモ帳レベルだけじゃなくて, vim-like, emacs-likeが選べるのでどっちか使える人には便利。
CloudPebbleは楽チンですばらしいのだが、唯一こまるのがスクリーンショットが撮れないこと(Linux環境だと撮れる(らしい))。
CloudPebble blog | What're we up to?(開発者Blog)を見ると最優先事項だと認識しているらしいので実装されると大変うれしい。
Android で画像処理
OpenCV も使ったり、画像取り扱いの基本
- OpenCV library を使うために前準備
libs に OpenCV-2.4.7-android-sdk\sdk\java\bin\opencv library - 2.4.7.jar をDrag&Drop
- OpenCV library の読み込み(ソースコード内で)
OpenCV Managerの呼出
Activityの実行直前に非同期に呼び出す(onResume()で呼び出すのはなんでだろう。onStart(), onCreate()じゃだめ?)
https://groups.google.com/forum/#!topic/android-opencv/LIixgr-iYSs
http://corkboard.ivory.ne.jp/?p=17
- setContentView()
XMLのレイアウトファイルを使う方法と実行時にViewを作る方法がある
http://www.javadrive.jp/android/activity/index4.html
http://allabout.co.jp/gm/gc/80740/
Android 開発環境整備
Windowsで開発環境を整えて、
実機デバッグ、OpenCVが使えるようになるまで。
- ADT(Android Developer Tools)
Android Studioでやろうと思ったけど、今回は挫折。
Eclipse + ADT Plugin のセットにしたアーカイブ。
http://developer.android.com/sdk/index.html
ADTに含まれるので不要
- USBドライバー
手持ちのAndroidスマホがSHARP製なので。
https://sh-dev.sharp.co.jp/android/modules/driver/
http://www.adakoda.com/android/000242.html
http://developer.android.com/tools/device.html
http://d.hatena.ne.jp/wize03/20130113/1358069204
- OpenCV SDK
http://www.kosaic.jp/wordpress/2012/12/opencv-for-android-2-4-3-2-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/
http://answers.opencv.org/question/14546/how-to-work-with-opencv4android-in-android-studio/
http://blog.bbtune.com/archives/1372/compiler-compliance-level-1-5-%E2%86%92-1-6-the-project-was-not-built-since-its-build-path-is-incomplete
- Android NDK(Native Development Kit)
CとかC++で開発するために必要らしい。特に使う予定はないが、OpenCVのサンプルのいくつかをコンパイルするために必要。
http://developer.android.com/tools/sdk/ndk/index.html
Kindle Paperwhite を買いました
- 出版社/メーカー: Amazon.co.jp
- 発売日: 2012/11/19
- メディア: エレクトロニクス
- 購入: 92人 クリック: 7,009回
- この商品を含むブログ (109件) を見る
3G版を買いました。Amazon.comで買った Kindle4 も持ってるのでそれとも比較してみます。
いいところ
- 喫茶店で本が買える
- バックライトがいい
1つ目は、わざわざ外で本を買うことなんてないからwifi版でもいいやと思ってたけど、
喫茶店とかで本をその場で買えるのは結構新鮮でした。
2つ目は、寝床に入って本を読むのにバックライトがなかなかよいです。
いまいちなところ
- 電池の持ちはKindle4より悪い
- wifi接続でないとメールを取得できない
1つ目の電池の持ちが悪いのは、3Gの待ち受けとバックライトの性だと思うのまぁしょうがないかな。無線を切る機能はあるけど、3Gだけ切れるようにもして欲しかった。
2つ目は自分の調査不足。3GはAmazonで書籍を買うためにしか使えないらしい。
ブラウザがつながらないのは知っていたけどメールも駄目なのね。
スマホで見つけて面白いページをその場でmobiに変換して、kindleに送って見れるかと思ったけど、できませんでした。
Amazonにすれば、何にもお金が落ちてこないから当たり前なのか。
でも、おおむね満足。
#漫画が危険w。手軽すぎて、読み終わったらついつい次の巻も購入してしまう。
Raspberry Pi でRuby
まずは、rvm(Ruby Version Manager)を下記を参考にしてインストール。
RVM
Linux で rvm を用いて Ruby をインストール
curl -L https://get.rvm.io | bash -s stable --ruby
対応するバイナリがないのでソースから自動的にコンパイルしてくれる。が、小一時間かかる。
次にrubygemsをupdate。
gem install rubygems-update
openssl ライブラリがないとかなんとか怒られるので、
sudo aptitude install libopenssl-ruby1.9.1
でいいかなぁと思ったけど駄目だった。ググると
rvm pkg install openssl rvm pkg install readline
が必要らしい。そんで、rubyをreinstallしろと言われるので素直に従う。
rvm reinstall all --force
で、rubyをソースからコンパイルするので小一時間待つ。
やっとこさrvmのインストール完了。こんな感じ。
pi@raspberrypi ~ $ rvm list rvm rubies =* ruby-1.9.3-p374 [ armv6l ] # => - current # =* - current && default # * - default
次にGPIOをたたくためのライブラリをインストールする。
RPi Low-level peripheralsを見るとRubyでRaspberryのGPIOをたたくには、WiringPi と Pi Piper の二つがあるらしい。
Pi Piperはイベントドリブン型。
RaspberryのGPIOをラジオのボリューム調整とチャンネル選択に使うので、今回はPi Piperの方がよさげなので、こちらをインストールする。
gem install pi_piper
まずは、ここまで。