AndroidをGPSロガーにする

Python mini Hack-a-thon (http://atnd.org/events/12812) での即興ネタ。

  
まずGoogleドキュメントにログインして、1行目に「latitude」「longitude」「timestamp」の3つのラベルをつけたスプレッドシートを作っておきます。
gdoc_config.pyにはGoogleドキュメントのアカウントを記述します。
gpslogger.pyの中のKEY、GIDには、先に作ったスプレッドシートのキーとワークシートIDを埋め込みます。なおワークシートID「od6」というのは「最初に作られたワークシート」の意味です。なんでそうなるかは不明。

(gdoc_config.py)

EMAIL = '...'  ## アカウント
PASSWORD = '...'  ## パスワード

(gpslogger.py)

import android
import sys
import time
import gdata.spreadsheet.service

from gdoc_config import EMAIL, PASSWORD
KEY = '...'  ## スプレッドシートのキー文字列
GID = 'od6'  ## スプレッドシートのワークシートID

droid = android.Android()
droid.startLocating()

for i in xrange(30):
  location = droid.readLocation()
  geo = None
  if location and location.result:
    result = location.result
    print result
    for src in (u'gps', u'network'):
      if result.has_key(src):
        geo = result[src]
        break
  if geo:
    break
  time.sleep(1)
else:
  droid.makeToast('timeout')
  sys.exit(0)

gd = gdata.spreadsheet.service.SpreadsheetsService()
gd.email = EMAIL
gd.password = PASSWORD
gd.source = 'gpslogger'
gd.ProgrammaticLogin()

data = {
  'latitude': str(geo['latitude']),
  'longitude': str(geo['longitude']),
  'timestamp': time.asctime(),
}
result = gd.InsertRow(data, KEY, GID)
if isinstance(result, gdata.spreadsheet.SpreadsheetsList):
  droid.makeToast('success')
else:
  droid.makeToast('fail')

droid.stopLocating()

汚い書き方で読みづらくて申し訳ないです。概要はこんな感じです。

  • 1秒おきに30回繰り返し、GPS情報の取得を試みる
  • 座標が取れなかったら終了
  • 座標が取れたらスプレッドシートに書き込む

APIは座標情報を辞書型で返しますが、キーは「gps」「network」の2種類あります。前者は内蔵GPSまたはBluetooth接続した外部GPSロガー等から取った場合、後者はおそらくGoogleAPIを使ったネットワーク情報ベースのようです。
ここではgps→networkの順に参照していますが、「network」の方はときどき間違った座標を返すことがあります(後述を参照)。確実にGPSデータが取れる端末であれば「gps」だけに固定した方がいいかもしれません。
startLocating()を実行してもすぐに座標が取れるようにはならないため、データが取れるまでreadLocation()を30秒間繰り返しています。ネットワーク情報ベースなら(ネットの速度によりますが)5〜20秒くらいで終わりますし、外部GPSロガーを使う場合も、自律的に測量したデータをBluetoothで引くだけなので比較的速く終わります。ただ内蔵GPSで万が一測量していない状態から始めたりすると1分で終わらないと思うので、状況によっては繰り返しの秒数を増やさないといけないと思います。

余談

デモで、リアルタイムでGoogleスプレッドシートに記録されていくのは結構興味深かったと思います。これはもちろんGoogleスプレッドシートがリアルタイムで画面書き換えをやってるからすごいのであって、SL4A + Py4Aがすごいわけではありませんw

余談2

ところでこのデモ中、最初は正しく会場(株式会社gumiさん)の座標が記録されていたのですが、途中から急に座標が変わり、長野県上田市のとあるおそば屋さん(1ヶ月前Python Hack-a-thon冬合宿で立ち寄った)の座標が記録されるようになってしまいました。
どうやらAndroidの座標取得APIは、GPSがあれば座標とIPアドレスとを結びつけてGoogle側に送り、ネットワーク情報ベースの測量ではそれを参照するだけ、という仕組みのようです。私は、おそば屋さんのとき外部GPSロガーを使い、今回のデモのときはネットワーク情報ベースで座標取得を行いました。このため、たまたまキャリアが同じIPアドレスを振ったか何かで、過去の座標を引っ張ってきてしまったようです。
takanory さんのような真っ当な端末(Nexus S)を使えば話は別ですが、私のように携帯回線を持たないAndroid端末で、日によってGPSロガー使ったりネットワークベースで座標取ったりすると、このような楽しい現象が起こるということに注意してください。
(ふつーの人はやらないと思いますが…)