0

WEB+DB Press vol.87でlittleBits/cloudBitについて書いた

数日前に発売されたWEB+DB Press vol.87で、littleBitscloudBitについて書きました。

WEB+DB PRESS Vol.87
WEB+DB PRESS Vol.87
posted with amazlet at 15.06.27
佐藤 鉄平 小林 明大 石村 真吾 坂上 卓史 上原 誠 鳥居 英 佐藤 歩 泉水 翔吾 うさみ けんた 伊藤 直也 高橋 侑久 佐藤 太一 hayajo 橋本 翔 西尾 泰和 中島 聡 はまちや2
技術評論社
売り上げランキング: 247

littleBitsは電子ブロックなんだけど、特殊なマグネットコネクタが使われているので回路が壊れるような向きには絶対接続できないようになっている。回路の知識が無くても大丈夫だし、酒飲みながら酔っ払って適当に接続してもショートしない。部品もセンサーとかモーターとか色々ある。

cloudBit

部品の中でもcloudBitというのは入出力がWebにつながっていて、HTTPで読み書きできるようになっている。IFTTTにもつながるので洗濯機の稼働が終わったことをサウンドトリガーセンサーで検知してSMSで通知するとか、色々な作例がインターネットに転がっている。

こういう風にするとWebからドアの鍵を回したりもできる。

cloudBit+door

記事では基本的なlittleBitsとcloudBitのAPIの使い方の解説と、HubotやYoと組み合わせた鍵貸し出しシステムについて書いた。
Hubotで「鍵あげる」「鍵返して」でゲストの鍵を管理し、DELTAS112(部屋名)にYoを送信すると開くというしくみ。


0

HerokuのHubotをProcess Schedulerで寝かす前に報告させる



HerokuのHubotを寝させる

無料で使うには1日6時間寝かせないとならないので
Heroku | Heroku’s Free (as in beer) Dynos

dashboard.heroku.comからaddonにProcess Schedulerを追加して6時間寝させる。


参考:HerokuでHubotを指定の時間に寝かせる – はらへり日記


寝る前に報告させる

寝る前に「寝ます」とか「寝ましょう」とか言ってくれた方が安心感がある。

herokuはプロセスの終了時にSIGTERMを投げてくるので、それを受ければいい。

nodeだとprocess.on(‘SIGTERM’, function(){ });でキャッチできるはずだけどHubotではできなかった。ソースをよく見たらbin/hubotが先にSIGTERMにイベントを登録して、その中でexitしていた。なのでSIGTERMイベントを上書きした。

module.exports = (robot) ->

## 起きた時、slack-adapterがつながるのを待って通知
cid = setInterval ->
return if typeof robot?.send isnt 'function'
robot.send {room: "#general"}, "ガバリ"
clearInterval cid
, 1000

## 寝た時、通知してからexitする
on_sigterm = ->
robot.send {room: "#general"}, 'スヤリ'
setTimeout process.exit, 1000

if process._events.SIGTERM?
process._events.SIGTERM = on_sigterm
else
process.on 'SIGTERM', on_sigterm

processがイベント管理に使っているEventEmitterは先に登録したイベントが先に実行される。先にbin/hubotが登録したイベントを削除するにはイベント登録時にreturnされるidを使うしか無いので、仕方なく_eventsプロパティを直接書き換えた。
hubotの仕様が変わった時に挙動がおかしくなるかもしれないけど、例えばsocket.ioがhttp.serverに/sockets/socket.io.jsを登録する処理とかでも_eventsの順序入れ替えをやっているし、まあしょうがない。EventEmitterとはそういう物だと思うしかない。

先に登録されていなければ普通にonで登録する。

本当は上書きじゃなくて先に実行されるようにしようかと思ったけど、eventemitterは登録されているコールバックが複数なら配列で持ち、1つなら配列ではなく関数を直接持つので、なんだか面倒になって上書きにした。

0

ブラウザ/NodeでKORG nanoKONTROL1/2を使えるライブラリをES6で作った

作った。

https://www.npmjs.com/package/korg-nano-kontrol

% npm i korg-nano-kontrol -save

ブラウザならWeb MIDI APIで、Nodeならmidi npmでMIDIコントローラと通信するようになっているのでrequireすればあとは適当に動く。
あと、最初coffeeで書いて全部完成したんだけどbabel(ES6)で書き直してみた。というのもES6は前々から使ってみたかったんだけど、1から機能を1つずつ勉強するのは苦手なので、既に慣れてるcoffeeの機能をフルに使ってある程度の大きさの物を実装してからES6で書きなおす事で色々な機能を一気に使わざるを得ない状況を作って勉強してみた。

KORG nanoKONTROLとは

EdisonとMIDIコントローラでHueを調光する
とか
Node.jsとMIDIコントローラでHueを調光する
で使っている便利なMIDIコントローラー。ツマミとスライダーがたくさん付いている。

もともとkorg-nanoというライブラリがある

んだけど、nanoKONTROL2に対応していなかったのと、修正しようにも2つのデバイスに対応するなら1から作ったほうが早そうな設計だったのでついでにWeb MIDI APIにも対応させて作ってみた。

使いやすかったのでAPIはほぼそのままにしてある。

使う


connect()するとPromiseが返ってくる
var nanoKONTROL = require('korg-nano-kontrol');

nanoKONTROL.connect()
.then(function(device){
console.log('connected!' + device.name);
// do something
})
.catch(function(err){
console.error(err);
});

で、

device.on('slider:0', function(value){ // スライダー0番を取得
console.log("slider:0 >>> "+value);
});
とか
device.on('knob:*', function(value){ // 全ノブ取得
console.log(this.event+' => '+value);
});
とかすると取れる。



Web MIDI API

ブラウザでもBrowserifyで固めれば同様に使える



EventEmitter2

EventEmitter2にはワイルドカードでイベントを受け取れる機能がある。上でdevice.on(“knob:*”, func)とかやってるのがそれ。

ES6ではclass nanoKONTROL2 extends EventEmitter2して、コンストラクタの中でsuper({wildcard: true, delimiter: “:”})したら有効になった。


coffeeからbabel(ES6)に書き直した

簡単に感想を列挙すると

coffee-scriptよりは機能が少ない。
coffeeのfor k,v of objでkey/valueを回せるのと、do (arg) ->でクロージャ即時実行と、添字付きfor文と後置if文が使いたい。
でもfor ofはES6組み込みクラスのMapをイテレータでfor [k,v] of Mapすればいいし、doはletがあれば必要ない。

unlessがほしい。ifに!つけるのつらい。
関数宣言する時にexport付ければexportできるのは便利。
テンプレート文字列もよい。
[3…8]みたいなのはlodashの_.range(3,8)で代用できる。
関数のデフォルトパラメータ指定便利。
classは違和感なく書ける。getter/setterやstaticの定義も便利。
for(let i of array)を使うとnode 0.12やChromeでは動くけど0.10やSafariでは動かないJSができる。Symbol is not definedエラーが出る。

coffeeで書くのに比べてコード量は1.3倍ぐらいになる。
でもまあ、node 0.12以上で動かすならどっちで書いてもいいかなという感じがした。
古い環境をターゲットにするならcoffeeの方が安心感がある。

ESLint

lintツールにESLintを使ってみた。coffee-lintより色々しっかり見てくれてる気がする。

.eslintrcを置くと全ルールがカスタムできてよい。

parserにbabel-eslintを指定するとES6がlintできる。


gruntやめてnpm runにした

参考:Grunt/Gulpで憔悴したおっさんの話 – MOL

grunt-babelが複数ファイルの変換設定がかっこよく書けないのと、gulpがやはり理解不能なのでコンパイルはbabel –watchでいいやと思った。

parallelshellで複数コマンド同時実行できるので、esw(eslint-watch)も一緒に実行してる。

あと、npm2.0からnpm run コマンド名 — 追加の引数という感じに–を挟むと引数を追加して実行できるので、babelのビルド設定をそのままに–watchを追加して実行できてよい。

watchという続けて書いたコマンドをファイル更新監視して実行してくれるnpmもあるんだけど、なんか反応が遅いのでeslint-watchとbabel –watchで良いやとなった。これだとEdison上でもサクサク動いて良い。
package.json
  "scripts": {
"test": "eslint src/*.es6 src/*/*.es6",
"build": "babel src/ --out-dir lib/ --source-maps inline",
"watch": "parallelshell 'npm run build -- --watch' 'esw src/ --watch'",
"buildSample": "browserify --debug samples/webmidi/src/main.js -o samples/webmidi/dist/bundle.js"
},

0

Edisonのnpmをupdateした

Edisonのnpmのバージョンが1.0系なのでnpm run test — –watchとかできなかったのでupdateした。

% npm update -g npm

したらnpmが壊れたので

module.js:340
throw err;
^
Error: Cannot find module 'npmlog'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at /usr/lib/node_modules/npm/bin/npm-cli.js:18:11
at Object. (/usr/lib/node_modules/npm/bin/npm-cli.js:75:3)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)


ソースからインストールしなおした。

% opkg install tar
% curl -0 -L https://www.npmjs.com/install.sh | sh
% npm --version
2.11.2

0

capybara-webkitでWebページのスクリーンショットを撮る

縦長のwebページを画像として保存したかったので久しぶりにcapybara-webkitを使った。


インストール

Macで使うにはqtが必要
% brew install qt
% gem install capybara-webkit

% gem list | grep capybara
capybara (2.4.4)
capybara-webkit (1.5.2)


キャプチャ

久しぶりに使ったらインタフェースが変わってたけど、ドキュメントが無いみたいなのでlib/capybara/webkit/driver.rbを読んで適当にやったらキャプチャできた。

capybara-capture.rb
require 'capybara-webkit'
require 'uri'

exit 1 if ARGV.empty?
url = ARGV.shift

driver = Capybara::Webkit::Driver.new 'capture'
driver.visit url
driver.save_screenshot "#{Time.now.to_i}_#{URI.parse(url).host}.png", :width => 1024, :height => 768
高さ指定しても縦長でキャプチャできる。

なおググるとせっかくDriverがbrowserをラップしているのになぜか直接driver.browserをいじっているコードがたくさん出てくる。



マウスを消したい

画面左上にマウスカーソルが出るのが気になる。消すAPIは用意されてない。
driver.execute_scriptでjavascriptが実行できるので、cssも書き換えられる。でもdocument.body.style.cursorや、driver.find(xpath)[0].hoverとか、画面外にdocument.createElementしてそこをhoverさせるとか色々やってみたけど無理だった。

今回はページ内の一部分が欲しかっただけなので、別にいいんだけど

他の手段

PhantomJSだとbody背景が透明になってしまうのでだめ。
Chrome拡張のFull Page Screen Captureだとページが長すぎるのか保存できなかった。