<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
		xmlns:xhtml="http://www.w3.org/1999/xhtml"
>

<channel>
	<title>クレコ &#187; 今ココなう！</title>
	<atom:link href="http://creco.net/tag/carry_out_here_now/feed/" rel="self" type="application/rss+xml" />
	<link>http://creco.net</link>
	<description>East or west, home is best.</description>
	<lastBuildDate>Fri, 27 Nov 2009 13:26:56 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/tag/carry_out_here_now/feed/" />
		<item>
		<title>今ココなう！のPythonクライアント作った</title>
		<link>http://creco.net/2009/07/17/carry_out_here_now_the_client_created_python/</link>
		<comments>http://creco.net/2009/07/17/carry_out_here_now_the_client_created_python/#comments</comments>
		<pubDate>Thu, 16 Jul 2009 22:05:35 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[作ってみた]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[今ココなう！]]></category>

		<guid isPermaLink="false">http://creco.net/2009/07/17/carry_out_here_now_the_client_created_python/</guid>
		<description><![CDATA[周りにはiPhoneのネイティブアプリ版を早く作れ！と言われてますが、時間がかかりそう（位置情報をポストするまではできたけど、ソフトとして完成させるとなるとと物足りないよねー）なので、簡単そうなPythonクライアント作 [...]]]></description>
			<content:encoded><![CDATA[<p>周りにはiPhoneのネイティブアプリ版を早く作れ！と言われてますが、時間がかかりそう（位置情報をポストするまではできたけど、ソフトとして完成させるとなるとと物足りないよねー）なので、簡単そうなPythonクライアント作ってみた。</p>
<p>簡単というのは、以前から自作のPythonクライアントを自分のライブトラッキングサーバ用に作っていたので、それを<a href="http://www.fujita-lab.com/imakoko/api.html">今ココなう！のAPI仕様</a>にあわせるだけだったり。</p>
<p>確認してないですが、Python実行環境を導入して、スクリプトを少し改造さえすればMacやLinuxなどでも使えると思うので、もしよかったら自由にお使いください。   <br />あと、自分のGPSロガーでしか確認していません、ごめんなさい。</p>
<p> <span id="more-713"></span><br />
<h3>ソース</h3>
<pre class="csharpcode">#!/usr/bin/python
# -*- coding: utf-8 -*-

# pySerial + Win32 Extensions(optional)
import sys, os, os.path, serial, urllib, urllib2, socket, thread, time, winsound

# Httpのタイムアウト値
socket.setdefaulttimeout(10)

# シリアルポートの設定
serialPort = <span class="str">'COM6'</span>

# 今ココなう！のユーザーIDとパスワード
userId = <span class="str">'USERID'</span>
userPassword = <span class="str">'USERPASSWORD'</span>

saveFlag = 1
markerType = 0

tryCount = 0
baseTime = 0

# NMEAセンテンスの読み取り
def getNmeaSentence():
    global baseTime

    <span class="kwrd">while</span> True:
        <span class="kwrd">try</span> :
            buffer = ser.read(1000)
        except :
            print <span class="str">&quot;error&quot;</span>
            <span class="kwrd">return</span> <span class="str">&quot;error&quot;</span>

        <span class="kwrd">if</span> <span class="kwrd">int</span>(time.time()) + baseTime - time.time() &gt; 0:
            time.sleep(<span class="kwrd">int</span>(time.time()) + baseTime - time.time() )

        # タイミング調整
        <span class="kwrd">if</span> buffer[0:6] != <span class="str">'$GPGGA'</span>:
            time.sleep(0.1)
            <span class="kwrd">if</span> baseTime &gt; 0.9:
                baseTime -= 0.9
            <span class="kwrd">else</span>:
                baseTime += 0.1
            print <span class="str">&quot;clock-timing adjustment...\n&quot;</span>
            <span class="kwrd">return</span>

        # GGAセンテンスの測位時刻の秒一桁が0
        <span class="kwrd">if</span> buffer[12:13] == <span class="str">'0'</span>:
            lines = buffer.split(<span class="str">&quot;\r\n&quot;</span>)

            data = [<span class="str">''</span>] * 12

            <span class="kwrd">for</span> line <span class="kwrd">in</span> lines:
                nmea = line.split(<span class="str">','</span>)

                <span class="kwrd">if</span> nmea[0] == <span class="str">'$GPGGA'</span>:
                    data[0] = nmea[1] # 測位時刻
                    data[1] = nmea[2] # 緯度
                    data[2] = nmea[3] # 北緯・南緯
                    data[3] = nmea[4] # 経度
                    data[4] = nmea[5] # 東経・西経
                    data[5] = nmea[6] # GPS測位状態
                    data[6] = nmea[7] # 受信衛星数
                    data[7] = nmea[8] # HDOP
                    data[8] = nmea[9] # 高度
                elif nmea[0] == <span class="str">'$GPRMC'</span>:
                    data[9] = nmea[7] # 対地速度
                    data[10] = nmea[8] # 進行方向
                    data[11] = nmea[9] # 測位日付

            # GPSが受信不能
            <span class="kwrd">if</span> data[5] == <span class="str">'0'</span>:
                print <span class="str">&quot;not receivable GPS data...&quot;</span>
                winsound.PlaySound(<span class="str">&quot;SystemQuestion&quot;</span>, winsound.SND_ALIAS)
                <span class="kwrd">return</span>

            args = (data,)
            thread.start_new_thread(putGpsData, args)

# Post
def putGpsData(args) :

    global tryCount

    print <span class="str">&quot;post...&quot;</span>

    gpsTime = time.strftime(<span class="str">&quot;%Y-%m-%dT%H:%M:%S&quot;</span>, time.localtime())
    gpsLatitudeD = <span class="kwrd">int</span>(<span class="kwrd">float</span>(args[1]) / 100)
    gpsLatitudeM = (<span class="kwrd">float</span>(args[1]) - gpsLatitudeD * 100)
    gpsLatitude = gpsLatitudeD + gpsLatitudeM / 60
    <span class="kwrd">if</span> args[2] == <span class="str">'S'</span>:
        gpsLatitude *= -1
    gpsLongitudeD = <span class="kwrd">int</span>(<span class="kwrd">float</span>(args[3]) / 100)
    gpsLongitudeM = (<span class="kwrd">float</span>(args[3]) - gpsLongitudeD * 100)
    gpsLongitude = gpsLongitudeD + gpsLongitudeM / 60
    <span class="kwrd">if</span> args[4] == <span class="str">'W'</span>:
        gpsLongitude *= -1
    gpsSpeed = <span class="kwrd">float</span>(args[9]) * 1.852 # knotをkm/hに変換

    <span class="kwrd">params</span> = {
        <span class="str">&quot;time&quot;</span> : gpsTime,
        <span class="str">&quot;lat&quot;</span> : gpsLatitude,
        <span class="str">&quot;lon&quot;</span> : gpsLongitude,
        <span class="str">&quot;gpsq&quot;</span> : args[5],
        <span class="str">&quot;gpsn&quot;</span> : args[6],
        <span class="str">&quot;gpsh&quot;</span> : args[8],
        <span class="str">&quot;gpsd&quot;</span> : args[10],
        <span class="str">&quot;gpsv&quot;</span> : gpsSpeed,
        <span class="str">&quot;save&quot;</span> : saveFlag,
        <span class="str">&quot;t&quot;</span> : markerType,
    }

    topLevelUrl = <span class="str">'imakoko-gps.appspot.com'</span>
    url = <span class="str">'http://imakoko-gps.appspot.com/api/post'</span>
    passMan = urllib2.HTTPPasswordMgrWithDefaultRealm()
    passMan.add_password(None, topLevelUrl, userId, userPassword)
    authHandler = urllib2.HTTPBasicAuthHandler(passMan)
    opener = urllib2.build_opener(authHandler)
    urllib2.install_opener(opener)

    <span class="kwrd">try</span>:
        urllib2.urlopen(url, urllib.urlencode(<span class="kwrd">params</span>))
    except urllib2.HTTPError, e:
        winsound.PlaySound(<span class="str">&quot;Notify&quot;</span>, winsound.SND_ALIAS)
        print e
    except urllib2.URLError, e:
        winsound.PlaySound(<span class="str">&quot;Notify&quot;</span>, winsound.SND_ALIAS)
        print e

    tryCount = tryCount + 1

    print tryCount
    print <span class="kwrd">params</span>
    print <span class="str">&quot;\n&quot;</span>

# シリアル接続
def connect() :
    global ser, baseTime

    <span class="kwrd">try</span>:
        ser = serial.Serial(serialPort, 38400, bytesize=8, parity=<span class="str">'N'</span>, stopbits=1, timeout=0.9, xonxoff=0, rtscts=0)
    except serial.SerialException, e:
        print e

    baseTime = time.time() - <span class="kwrd">int</span>(time.time());

    <span class="kwrd">while</span> True:
        <span class="kwrd">if</span> getNmeaSentence() == <span class="str">&quot;error&quot;</span>:
            ser.close()
            <span class="kwrd">return</span>

    ser.close()

# メインループ
<span class="kwrd">while</span> True:
    connect()
    time.sleep(5)
    print <span class="str">&quot;reconnect...&quot;</span></pre>
<h3>解説<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</h3>
<h4>導入するもの</h4>
<ul>
<li>Python実行環境</li>
<li>pySerial</li>
<li>Win32 Extension（場合によっては必要ないかも）</li>
</ul>
<h4>やっていること</h4>
<ol>
<li>メインでGPS接続試行でぐるぐる</li>
<li>GPSにシリアル接続（ボーレートとかは調節してね。なんでタイムアウトが0.9なのかは謎）</li>
<li>1秒ごとにNMEAセンテンスを読み取る。読み取るタイミングを調節</li>
<li>調節がうまくいったら、10秒ごとにGGAとRMCのセンテンスを読み取る</li>
<li>BASIC認証で今ココなう！APIにPOSTする</li>
</ol>
<p>ぼくの場合、自転車での使用を想定していて、メッセージを目視することはできないので、なんらかのエラーが起きた場合に視覚以外で知る必要があります。なので、GPS情報が取得できない場合と、POSTがうまくいかなかった場合はそれぞれサウンドがなるように設定しています。</p>
<h4>以上です。</h4>
<p>Pythonがある程度わかる人前提なので、そんなに説明することないですね。逆に、なんでこんなシリアル接続パラメーターなのかとか、タイミングの取り方でもっとスマートなやり方とか、スレッド使うときにタプルで引数を渡すのはなんで？とか教えてもらいたかったり。</p>
<h6></h6>
<h5>今ココなう！実装済み環境</h5>
<ul>
<li>Android Chrome Lite + Google Gears、各種ブラウザ + Google Gearsアドオン</li>
<li>iPhone Mobile Safari (OS 3.0以上)、Firefox 3.5以上、Safari 3.0以上</li>
<li>Python <strong>New!</strong></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2009/07/17/carry_out_here_now_the_client_created_python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2009/07/17/carry_out_here_now_the_client_created_python/" />
	</item>
	</channel>
</rss>
