はかますたいる!きょろの技的雑記

井上恭輔(@kyoro353)の私的かつ技的な日記です。米国サンフランシスコで暮らすエンジニアです。

JINS MEME + MQTT + Node.js で、目が疲れて遠くを見つめた時に勝手にMacの画面を消してくれる便利な奴を作る

f:id:kyoro353:20151214210624g:plain

こんにちは、きょろです。

この記事は JINS MEME Advent Calendar 2015 - Qiita の15日目です。

やったこと

タイトルの通りですが、まとめサイト閲覧中 コーディング中に目が疲れて遠くを見つめた時に、Macの画面を勝手に消して光量を落とし、リラックスを手助けしてくれるプログラムを作ってみました。

といっても、もちろんアプリを本気で作る訳ではなくて、JINS MEMEのデータをクラウド経由で常に周囲のパソコンやIoTデバイスに送りつけると、どんな楽しいことができるかな?」というコンセプトで、JINS MEMEのセンサーデータをMQTTを使って外部に送り、受信したプログラム側で色々遊ぶという事をためしてみたいと思います。

なんで外部サーバ+MQTT?

直接パソコンにデータを送るのであれば、mito_logさんのアドベントカレンダー8日目「JINSMEME - JINS MEMEのデータをtcp socket通信で出力、Processingに流してグラフ化してみる - Qiita」が良くまとまって書かれているのでぜひご参考ください。

今回、外部サーバを経由してデータをやり取りするのは「日常でいつも自然に身に付ける事ができる」というJINS MEMEのメリットを活かして、できるだけ特殊な設定やネットワーク環境&設備の制約が一切なく、ネットに繋がってさえいれば、アプリを立ち上げるだけすぐに使えるJINS MEMEの応用例を考えてみようと思ったからです。 たとえば

-「スタバでMacBookを開いたら、既にJINS MEMEが繋がって画面制御ができる」 -「家に帰ったら家電がJINS MEMEと自動で連携して動き出す」

みたいなIoTな世界を体験することができます。

一般的にMQTTを使うメリットには、以下の様な事があります。これはJINS MEMEを使った、特にリアルタイムの通信を伴うアプリを作る際にも有用です。

  • プロトコルとして軽量
  • プッシュ用途で扱いやすい
  • IoT用途で組み込み機器で実装する際も負荷が小さい
  • ライブラリも整っている

f:id:kyoro353:20151214214818p:plain

今回のデモでは、JINS MEMEから頭の傾きデータを受けたiPhoneアプリが、MQTTでブローカー(サーバー)にセンサーデータをパブリッシュし、MQTTブローカーを経由して、Mac側でサブスクライブしているNode.jsのアプリにデータを受け渡します。そして受け取ったデータを元に、Node.jsのプログラム側で画面の点灯制御を行います。

MQTTブローカーを用意する

それでは実際に開発に入りましょう。まず、データを中継するMQTTブローカー(サーバ)を用意しましょう。 これはMQTTブローカーであればぶっちゃけ何でも良いです。流行りのAWS IoTを使ってもいいですし、SangoMilkcocoaでも良いです。 私はMosquittoを使ってUbuntu上に自分でMQTTサーバを立てました(とっても簡単です) 興味がある人は私の過去の記事で詳しくまとめていますので、ぜひ参考にしてみてください。

kyoro353.hatenablog.com

iPhoneアプリを作る

さて、次はiPhoneアプリを作り、JINS MEMEのセンサーデータをMQTTブローカーに投げつけましょう。 と言っても、1から作るのは面倒くさいので、今回はJINS MEMEのデベロッパーサイトで配布されているリアルタイムデータ取得のサンプル(MEMELib_RealTime)を改造していきます。

MQTTKitの導入

MQTTブローカへの接続には、クライアントライブラリのMQTTKitを使います。 podでサクッと入るので、MEMELib_RealTimeのプロジェクトに追加しましょう。

platform :ios,'8.0'
pod 'MQTTKit', :git => 'https://github.com/mobile-web-messaging/MQTTKit.git'

注意点として、pod導入後、Build SettingsのBuild Active Architecture OnlyをYESにしましょう。そうしないと、JINS MEMEのSDKの都合でビルドが通りません。

MMDataViewController.mの改造

あとは簡単な改造です。データ取得の大部分は既存のサンプルを使うので、MQTTブローカへの送信部分だけ追加で実装しましょう。 まずは、MQTTKitのヘッダーを読み込みます。

#import <MQTTKit.h>

次に必要なプロパティを追加

@property MQTTClient *client;
@property BOOL mqttConnected;
@property NSTimeInterval lastSentTimestamp;

viewDidLoadedには、MQTTブローカへの接続ロジックを記述します。

    // connect to the MQTT server
    _mqttConnected = NO;
    _lastSentTimestamp = 0;
    NSString *clientID = @"MEME-Client";
    _client = [[MQTTClient alloc] initWithClientId:clientID];
    [self.client connectToHost:@"your-mqtt-broker.com"
             completionHandler:^(NSUInteger code) {
                 if (code == ConnectionAccepted) {
                     _mqttConnected = YES;
                     NSLog(@"MQTT Connected");
                 }
             }];

あとは、データを送りつけるメソッドを用意します。JINS MEMEのデータ取得レートは結構速いので、さすがにMQTTと言えど、Unixtimeを見て毎秒1回の送信程度に制限します。 トピックは受信側のプログラムと揃えれば何でもいいです。今回は頭のピッチ方向(上下)の傾きしか使わないので、「pitch:」というフォーマットで送信します。

-(void)sendDataToMQTTServer: (MEMERealTimeData*) data
{
    if(!_mqttConnected){
        return;
    }
    NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
    if((timeStamp - _lastSentTimestamp) > 1){
        _lastSentTimestamp = timeStamp;
        [self.client publishString:[NSString stringWithFormat:@"pitch:%f",data.pitch]
                           toTopic:@"meme"
                           withQos:AtMostOnce
                            retain:NO
                 completionHandler:^(int mid) {
                     NSLog(@"message has been delivered");
                 }];
        NSLog(@"Send pitch:%f", data.pitch);
    }
    
}

最後に、memeRealTimeModeDataReceivedの最後に先ほど記述したデータ送信メソッドを呼び出す処理を書き足せば完成です。

[self sendDataToMQTTServer:data];

Node.js側のプログラムを書く

それではMacで動かすNode.js側のプログラムを作りましょう。 の前に、Macの画面の輝度を制御する、その名も「brightness」という簡単なコマンドがあるので、先立ってそれをbrewで導入しましょう。

brew install brightness

また、MQTTライブラリが必要なので、npmでインストールしましょう。

npm install mqtt

コードを記述します。こちらはフルスクラッチで書いたので、JINS MEME SDKと違いライセンスが自由です。 ライセンスはとりあえずMITにしておきますのでご自由にお使いください。極めて短いです。

頭の確度は上を向くほど小さくなりますので、今回はいい感じになった-15°と決め打ちにしています。 状況にあわせて変えてください。

以上で開発は終わります。簡単ですね! 完成したらiPhoneアプリとNodeのプログラムを動かし、JINS MEMEを接続して、上を向いてみてください。画面が消えましたか?!(上を向いたのでモニタが見えないかもですが) こんな感じで、JINS MEMEを使って、iPhoneアプリ意外の物を簡単に連携させることができました。

気付かないうちにJINS MEMEが生活と連携する世界って面白い

まとめです。今回はJINS MEMEとNode.JSをMQTTで繋ぎ、リアルタイムに動作するプログラムを作成しました。 今回は簡単に頭の傾きを使いましたが、もっとJINS MEMEらしく「目を閉じた時」とか「集中力が下がった時」なんかをトリガーにすると、もっと面白いかもしれませんね。 JINS MEMEの何よりの良さは「使っていることを忘れる」レベルに自然に日常使いができるという所だと思います。実際、今回は単なるデモアプリでしたが、このブログ記事を書いたる間にふと遠くを見つめたときにMacの画面が消えて、おおっ!と思いました。「意識しなくていい」というのは、とても大切なUXだなと再認識しました。 JINS MEMEが、それこそ「接続」や「設定」などの意識的な動作が不要に、気づかないうちに空間や世界と連携しているような未来が来ると面白いな、と思いました。

f:id:kyoro353:20151214225622j:plain