JINS MEMEのデータをxx秒おきにGoogle SpreadSheetに流す

  • 11
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

What's JINS MEME

こちらをご参考ください。
http://qiita.com/mito_log/items/020a87996ed2b9d793e6

Motivation

JINS MEMEを使って何か作るにもデータの傾向を見たり分析してからでないとなぁ。ということでxx秒ごとにgoogle spread sheetに投げてデータを見てみます。今回も前回に引き続きRxSwiftで頑張っております。

github

https://github.com/mitolog/JINSMEMESampler

Spreadsheet

https://docs.google.com/spreadsheets/d/196kFM695twoL4b_a8dv-4AKrBZQW4jJk9MqcQyCgf4g/edit?usp=sharing

Screenshots

iPhone
MEME_spreadsheet_iphone.png

spreadsheet
MEME_spreadsheet_spreadsheet.png

How it works

ios側では、データを一旦配列に貯めておいて、一定時間毎にcsvでデータをpostで送信しています。

google spreadsheet側では、google app scriptのContent Serviceという機能を使い、簡単なRestfulAPI(POSTのみ)を用意しています。そこで、csvをパースして、シートに転記しています。

google apps scriptを使ったAPIについては、過去に書いた記事を見つつ作れるかと思います。注意すべきは、

  • スプレッドシート名を固有のものにすること
  • アプリの実行権限を得ること
  • ウェブアプリケーションとして導入のオプション

くらいかと思います。

Recap

Too much memory use while data retrieval and sending

今回もRxSwiftを使ってみたのですが、dispose関連のタイミングやら手法がまだカバーできていないせいか、データ取得時に大量にメモリを食ってしまっています。一応leaksでみてみるとリークは無いとの判定でしたが、工夫したいところです。

takeUntil

今回、スタート/ストップボタンを押すと、「データの取得開始、タイマーの起動」をしています。つまり、
スタート:subscribeの開始
ストップ: dispose
としたかったのですが、disposeをどうやるべきか...紆余曲折を経てtakeUntilを使う手法にたどり着きました。

takeuntil.png
画像: RxSwiftのPlaygroundより

一番上をrealtimeDataを取得するシーケンス(MEMELibAccess.sharedInstance.rx_realtimeDataReceived)、そのすぐ下を、データストップシーケンス(stopSequence)とすると、stopSequenceに何かしら次のアイテムをセットした時点で一番上のシーケンスは完了扱いとなり、disposeされます。

コード上でいくと、

MEMELibAccess.sharedInstance.rx_realtimeDataReceived
            .takeUntil(self.stopSequence)
            .subscribeNext { [unowned self] realtimeData in

というふうにせっとしておいて、その後に、stopSequence.on(.Next(true))とかしてあげればOKです。

詳しくは、GettingStartedのDisposingの箇所を見るといいかと思います。

bi-directional binding

RxSwiftで双方向データバインディングをみながらやってみました。

とても柔軟だなとおもったのは、例えばモデルがdoubleでビューがstringでもバインドできます。

view_to_model
self.intervalTextField.rx_text.subscribeNext { [unowned self] intervalStr in
    if intervalStr.utf16.count > 0 {
        self.vm.interval.value = atof(intervalStr)
    }
}.addDisposableTo(self.disposeBag)
model_to_view
self.vm.interval
    .subscribeOn(MainScheduler.sharedInstance)
    .map { interval in
        return String(interval)
    }
    .bindTo(self.intervalTextField.rx_text)
    .addDisposableTo(self.disposeBag)

mapを噛ませて、stringを返すようにすればバインドできました。

Scheduler

今回のように通信が絡んだりタイマーが絡むと、UIスレッドを意識しないといけません。RxSwiftでもスケジューラーという概念でスレッドを管理できるようになっているので、スケジューラーは要チェックです。

https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Schedulers.md

1点気になったのが、ドキュメントでは、.subscribeOn(MainScheduler.sharedInstance)すればメインスレッドでsubscribeできるよみたいに書いてあったのですが、一部効かない場所があったので、dispatch_async(dispatch_get_main_queue()) {}で対応しました。

20Hz

いきなりJINS MEMEのことになりますが(ていうかほぼRxSwiftの勉強になっていますね...)、JINS MEMEのrealtimeモードでは、通信速度がBluetooth通信周期にのっとって約20Hzとなっています。
参照: https://developers.jins.com/ja/

ということは、1秒間に約20サンプルのデータがiPhoneには送られていることになり、10秒だと約200のサンプルになります。

google spreadsheetの最大セル数は、200万セルということなので、逆算すると、

2000000セル / 16(1行分のセル数) / 20サンプル = 6250秒(約104分)

は貯められることになりますが、用途としては、突発的な動作や短いスパンでの変化を分析したいときに使えるかなと思いました。

ということで、引き続きデータを見ながらどんなことができそうかを探っていきます。

この投稿は JINS MEME Advent Calendar 20156日目の記事です。