2013年3月3日日曜日
GAEでpython-on-a-chipオンラインコンパイラの試作
python-on-a-chip(pymite)でpythonコードを変更するたびに mbed の C++コンパイラを通すのは面倒なので、オンラインで直接実行ファイルを作れるか試してみました。
Google App Engine(GAE) で作ったWEBサイトでpythonコードを入力。
compileコンパイルボタンを押すと、pmImgCreator.py でバイトコードに変換、実行ファイルのバイトコードを入れ換えて、パソコンにダウンロードさせる。
mbedにドラッグアンドドロップで実行します。
厳密にテストしてはないのですが、python2.5 の pmImgCreator.py で作るバイトコードは動くようです。
そのために GAE では 2.7 が使えるのに、あえて python2.5 で動かしています。
jinjia2 はGAEローカル開発環境では動くが、オンライン環境では 2.7 が必要で、旧テンプレートエンジンを使用しなければならない。
簡単にWEBサイトを作るために、jQuery Mobile を使用しているのだが、ファイルのダウンロードはうまくいかない。
フォームでは ajax をディセーブルにする必要があります。
GAEでの試作例サイト:
http://pymbed.appspot.com/
GAEでの実行コード:
https://bitbucket.org/va009039/pymbed
python-on-a-chip実行ファイル作成のコード:
http://mbed.org/users/va009039/code/pymite/
mbedコンパイラへのインポートを助けるためのバッチファル make.bat:
http://mbed.org/users/va009039/code/pymite/wiki/makebat
オフラインコンパイルのためのバッチファイル compile.bat:
http://mbed.org/users/va009039/code/pymite/wiki/compilebat
(2013/3/3)
---
ラベル:
GAE,
jQuery Mobile,
mbed,
Python
2013年1月23日水曜日
cosmのトリガーでメールを送る

cosmのトリガーHTTP POSTでGAEを叩いてメールを送っていたが、
メールの送り先をGAEの管理者に変更してみた。
管理者メールはGmailで登録しているので、フィルターで携帯電話に転送している。
センサーmbed → cosm → GAE → gmail → 携帯電話
15分間データの更新が無いとfrozenのトリガーがあるのでmbedが無反応になったのもわかります。
# cosmtrigger.py 2013/1/23
#coding: utf-8
import webapp2
from google.appengine.api import app_identity
from google.appengine.api import mail
class TriggerHandler(webapp2.RequestHandler):
def post(self, param):
json_str = self.request.get('body')
mail.send_mail_to_admins(
sender = "cosmtrigger@" + app_identity.get_application_id() + ".appspotmail.com",
subject = "cosm trigger %s" % param, body = json_str)
app = webapp2.WSGIApplication([
(r'/cosmtrigger/(.*)', TriggerHandler),
], debug=True)
(2013/1/23)
---
2012年12月8日土曜日
PythonでARMv7Mの逆アセンブラをつくる
mbedのコンパイラがどんなコードを出力するのか知りたかったので、PythonでARMv7Mの逆アセンブラをつくってみました。
dasv7m
GAEでも動くようにしてみました。
disassembler
たとえばLEDチカチカを逆アセンブラすると次のようになります。
(printf("%p\n", main);はmain()のアドレスを知るために追加してあります)

(2012/12/8)
---
dasv7m
GAEでも動くようにしてみました。
disassembler
たとえばLEDチカチカを逆アセンブラすると次のようになります。
(printf("%p\n", main);はmain()のアドレスを知るために追加してあります)
#include "mbed.h"
DigitalOut myled(LED1);
int main() {
printf("%p\n", main);
while(1) {
myled = 1;
wait(0.2);
myled = 0;
wait(0.2);
}
}

(2012/12/8)
---
2012年9月30日日曜日
2012年9月9日日曜日
JPEGからDHTセグメントを削除するプログラム
Windows7でGoogle ChromeはJPEGファイルのDHTセグメントが無くても表示できるが、IEでは表示できない。
Google製のPicasaでも表示できない。もちろんペイントでも表示できない。

mbedでUVCカメラを扱うプログラムを作成していた時に、なぜかロジクールのカメラだけ表示出来ない事に気がついた。調べてみるとロジクールのカメラから送られて来るモーションJPEGはDHTセグメントは付いていない。
表示できるようにJPEGファイルを変換する(DHTを付加する)Webサービスを作ろうと考えて、
アップロードしたファイルを出力するだけのプログラムを作ったら、Chromeだけ表示できる事がわかった。
最近、WebcamServerが表示できないという苦情が来た。ロジクールのカメラの場合はChromeを使えばいいと考えて
DHTはあえて付加していなかった。Chromeを使うようにお願いしても表示できない、MacのChromeらしい。
WebcamServer側でDHTを付加するように修正したら表示できると報告されたので、WindowsとMacではChromeの
仕様は違うのかもしれない。
サイト:http://va009039-mbed.appspot.com/jpeg/DHTstrip/
ソースコード:jpeg_DHTstrip.py
---
Google製のPicasaでも表示できない。もちろんペイントでも表示できない。

mbedでUVCカメラを扱うプログラムを作成していた時に、なぜかロジクールのカメラだけ表示出来ない事に気がついた。調べてみるとロジクールのカメラから送られて来るモーションJPEGはDHTセグメントは付いていない。
表示できるようにJPEGファイルを変換する(DHTを付加する)Webサービスを作ろうと考えて、
アップロードしたファイルを出力するだけのプログラムを作ったら、Chromeだけ表示できる事がわかった。
最近、WebcamServerが表示できないという苦情が来た。ロジクールのカメラの場合はChromeを使えばいいと考えて
DHTはあえて付加していなかった。Chromeを使うようにお願いしても表示できない、MacのChromeらしい。
WebcamServer側でDHTを付加するように修正したら表示できると報告されたので、WindowsとMacではChromeの
仕様は違うのかもしれない。
サイト:http://va009039-mbed.appspot.com/jpeg/DHTstrip/
ソースコード:jpeg_DHTstrip.py
---
2012年4月22日日曜日
PachubeクライアントをGAEでデバッグする
Pachubeクライアントをデバッグする時に、ヘッダーに入れたキーが正しいか,
POSTしたデータ形式が正しいかをGAEでPachubeのAPIを作って調べる。
POSTしたデータ形式が正しいかをGAEでPachubeのAPIを作って調べる。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# gae_PachubeClient_debug.py 2012.4.21
import logging
import os
import re
import time
import datetime
import StringIO
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class pachubeHandler(webapp.RequestHandler):
def post(self,feeds):
logging.info(feeds)
method = self.request.get('_method')
logging.info(method)
headers = self.request.headers
apikey = headers.get('X-PachubeApiKey')
logging.info(apikey)
body = self.request.body
logging.info(body)
self.response.out.write(" ")
application = webapp.WSGIApplication([
(r'/v2/feeds/(\d+)\.csv', pachubeHandler),
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
---2012年3月13日火曜日
GAE/Pythonでtar.gzを解凍する
美咲フォントのBDF形式を扱いたかったので、まずは、Pythonでtar.gz形式の書庫を解凍するプログラムを組んでみた。
---
# -*- coding: utf-8 -*-
# gae_untargz.py 2012.3.13
import logging
import os
import StringIO
import tarfile
from google.appengine.api import users
from google.appengine.api import memcache
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
class untargz(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
prefix = user.user_id()
logging.info(prefix)
targz_file = memcache.get(prefix + 'targz_file')
filename = memcache.get(prefix + 'filename')
action = self.request.get('action')
member = self.request.get('member')
members = []
if targz_file:
fileobj = StringIO.StringIO(targz_file)
tar = tarfile.open(fileobj = fileobj, mode = 'r:gz')
if action=='view':
f = tar.extractfile(member)
self.response.headers["Content-Type"] = "text/plain"
self.response.out.write(f.read())
return
for tarinfo in tar:
members.append(tarinfo.name)
template_values = {'filename': filename, 'members': members, 'action': action}
path = os.path.join(os.path.dirname(__file__), "templates", "untargz.html")
self.response.out.write(template.render(path, template_values))
def post(self):
user = users.get_current_user()
prefix = user.user_id()
targz_file = self.request.get('targz_file')
if targz_file:
filename = self.request.body_file.vars['targz_file'].filename
memcache.set(prefix + 'targz_file', targz_file, 180)
memcache.set(prefix + 'filename', filename, 180)
self.redirect('/untargz?action=list')
application = webapp.WSGIApplication([
('/untargz.*', untargz),
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
---
2011年9月25日日曜日
DS18B20とmbedでデジタル温度計を試作(2)
実際の環境で使えるように改良。
・温度センサーを3.5ミニプラグに収めてみた。
ブレッドボードに刺さっている3.5ミニジャックはスイッチサイエンスのオーディオジャック+ピッチ変換基板のセットです。
・GAE以外にもPachubeにデータを送信するようにした。
・PachubeのトリガーでGAEを叩いてメールを送信するようにした。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# gae_ds18b20.py 2011.9.25
import logging
import datetime
from django.utils import simplejson
from google.appengine.api import app_identity
from google.appengine.api import mail
from google.appengine.ext import webapp
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
import owner_cfg
class ds18b20(db.Model):
realTemp = db.FloatProperty()
created = db.DateTimeProperty(auto_now_add=True)
@property
def created_jst(self): # 日本時間(テンプレートエンジン用)
return self.created + datetime.timedelta(hours=9)
class ApiHandler(webapp.RequestHandler):
def get(self, realTemp):
data = ds18b20()
data.realTemp = float(realTemp);
data.put()
self.response.out.write("RealTemp: %s" % realTemp)
class EmailHandler(InboundMailHandler):
def receive(self, mail_message):
message = mail.EmailMessage()
message.sender = "ds18b20@" + app_identity.get_application_id() + ".appspotmail.com"
message.to = mail_message.sender
message.subject = u"DS18B20"
query = ds18b20.all()
data = query.order("-created").get()
message.body = u"RealTemp: %f" % data.realTemp
message.send()
class TriggerHandler(webapp.RequestHandler):
def post(self, param):
json_str = self.request.get('body')
logging.info(json_str)
obj = simplejson.loads(json_str)
logging.info(obj)
message = mail.EmailMessage()
message.sender = "ds18b20-trigger@" + app_identity.get_application_id() + ".appspotmail.com"
message.to = owner_cfg.to
message.bcc = owner_cfg.bcc
message.subject = u"DS18B20 TRIGGER %s" % param
message.body = json_str
message.send()
application = webapp.WSGIApplication([
('/ds18b20/api/(.+)', ApiHandler),
('/ds18b20/trigger/(.*)', TriggerHandler),
EmailHandler.mapping(),
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
---
2011年9月18日日曜日
DS18B20とmbedでデジタル温度計を試作(1)
mbedに1-Wire温度センサDS18B20を接続してデジタル温度計を試作してみた。(奥に見えている白いのはDHT22で今回の試作には関係ありません)
うっかりしていたが、寄生電力モード(parasitic mode)で動かすときにはプルアップ抵抗4.7KΩでは大きい、2.2KΩにしたら動いた。
mbedではOneWireCRCにHTTPClientを追加して温度データを一定間隔でGAEにアップロードしています。
ケータイからメールリクエストで温度データを読み取ります。
以下はGAE側で動かしているソフトウェアです。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# gae_ds18b20.py 2011.9.17
import datetime
from google.appengine.api import app_identity
from google.appengine.api import mail
from google.appengine.ext import webapp
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
class ds18b20(db.Model):
realTemp = db.FloatProperty()
created = db.DateTimeProperty(auto_now_add=True)
@property
def created_jst(self): # 日本時間(テンプレートエンジン用)
return self.created + datetime.timedelta(hours=9)
class ApiHandler(webapp.RequestHandler):
def get(self, realTemp):
data = ds18b20()
data.realTemp = float(realTemp);
data.put()
self.response.out.write("RealTemp: %s" % realTemp)
class EmailHandler(InboundMailHandler):
def receive(self, mail_message):
message = mail.EmailMessage()
message.sender = "ds18b20@" + app_identity.get_application_id() + ".appspotmail.com"
message.to = mail_message.sender
message.subject = u"DS18B20"
query = ds18b20.all()
data = query.order("-created").get()
message.body = u"RealTemp: %f" % data.realTemp
message.send()
application = webapp.WSGIApplication([
('/ds18b20/api/(.+)', ApiHandler),
EmailHandler.mapping(),
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
(2011/9/18)
---
2011年8月15日月曜日
プリモバイルでみまもりケータイからの位置情報付きメールを地図表示する
プリモバイルではインターネットに接続できない。
みまもりケータイから送られて来た位置情報付きメールのURLを開くことは出来ない。
プリモバイルのメールし放題でGAEに転送して、代わりに地図の画像を取得して返信してもらう。
地図の画像の取得にはYahoo!デベロッパーネットワークのスタティックマップAPI、住所取得にはリバースジオコーダAPIを使っています。
---
みまもりケータイから送られて来た位置情報付きメールのURLを開くことは出来ない。
プリモバイルのメールし放題でGAEに転送して、代わりに地図の画像を取得して返信してもらう。
地図の画像の取得にはYahoo!デベロッパーネットワークのスタティックマップAPI、住所取得にはリバースジオコーダAPIを使っています。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# mimamori_simplemap.py 2011.8.3
import logging
import os
import datetime
import re
import urllib
from django.utils import simplejson
from google.appengine.api import app_identity
from google.appengine.api import urlfetch
from google.appengine.api import mail
from google.appengine.ext import webapp
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
from google.appengine.ext.webapp.util import run_wsgi_app
import yahoo_dev
def getgeo(text):
pat = r'N(?P\d+)\.(?P\d+)\.(?P\d+\.\d+)E(?P\d+)\.(?P\d+)\.(?P\d+\.\d+)'
m = re.search(pat, text)
if m:
lat = float(m.group('d1')) + float(m.group('m1')) / 60 + float(m.group('s1')) / 3600
lon = float(m.group('d2')) + float(m.group('m2')) / 60 + float(m.group('s2')) / 3600
return (lat, lon)
else:
return None
def yahoo_static_map(geo):
api_url = "http://map.olp.yahooapis.jp/OpenLocalPlatform/V1/static"
params = {
'appid': yahoo_dev.my_appid,
'pin': str(geo[0]) + "," + str(geo[1]),
'width': "480",
'height': "480",
'z': "19",
}
query = urllib.urlencode(params)
result = urlfetch.fetch(api_url + '?' + query)
if result.status_code == 200:
return result.content
else:
return None
def yahoo_revgeo(geo):
api_url = "http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder"
params = {
'appid': yahoo_dev.my_appid,
'lat': str(geo[0]),
'lon': str(geo[1]),
'output': 'json',
}
query = urllib.urlencode(params)
result = urlfetch.fetch(api_url + '?' + query)
if result.status_code == 200:
json_str = result.content
obj = simplejson.loads(json_str)
address = obj['Feature'][0]['Property']['Address']
logging.info(u"位置情報:" + address)
return address
else:
return u"位置情報は取得できませんでした."
class simplemap_email(InboundMailHandler):
def receive(self, mail_message):
path = self.request.path
logging.info("path: " + path)
logging.info("Received a message from: " + mail_message.sender)
body_text = image_data = ""
plaintext = mail_message.bodies(content_type='text/plain')
for text in plaintext:
txtmsg = text[1].decode()
logging.info("Body is %s" % txtmsg)
geo =getgeo(txtmsg)
logging.info(geo)
if geo:
body_text = yahoo_revgeo(geo)
image_data = yahoo_static_map(geo)
break
message = mail.EmailMessage()
message.sender = "simplemap@" + app_identity.get_application_id() + ".appspotmail.com"
message.to = mail_message.sender
message.subject = u"位置情報 " + mail_message.subject
message.body = u"現在地:\n" + body_text
if image_data:
message.attachments = [("map.png", image_data)]
message.send()
application = webapp.WSGIApplication([
simplemap_email.mapping(),
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
---
2011年3月8日火曜日
GAEで対応クライアントをZIPファイルで配布する
GAEで作ったサーバーからクライアントソフトウェアをダウンロードして展開して実行するだけにしたい。
サーバーでAPIのURLやアプリキー等を書いた設定ファイルと実行ファイルをZIPファイルに纏めてダウンロードさせます。
サーバーでAPIのURLやアプリキー等を書いた設定ファイルと実行ファイルをZIPファイルに纏めてダウンロードさせます。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# download.py 2011.3.7
import os
import logging
import urlparse
import random
import zipfile
import StringIO
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import login_required
from google.appengine.ext.webapp.util import run_wsgi_app
class download(webapp.RequestHandler):
@login_required
def get(self, filename):
output = StringIO.StringIO()
zip = zipfile.ZipFile(output, 'a')
user = users.get_current_user()
o = urlparse.urlparse(self.request.url)
api_url = "http://" + o.netloc + "/api"
appkey = "%08x" % random.randint(0x10000000, 0xffffffff)
template_values = {'appkey': appkey, 'user_id':user.user_id(), 'api_url': api_url}
path = os.path.join(os.path.dirname(__file__), "client", "client.ini")
zip.writestr("client.ini", template.render(path, template_values))
path = os.path.join(os.path.dirname(__file__), "client", "client.py")
zip.write(path, "client.py")
zip.close()
self.response.headers['Content-Type'] = "application/zip"
self.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % filename
self.response.out.write(output.getvalue())
application = webapp.WSGIApplication([
('/download/(client.zip)', download),
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
2011年2月5日土曜日
ネットワークカメラからのメールをGAEで受信する
ネットワークカメラTS-LCAMの「動きを検知するとメールを送信する」設定にすると膨大なメールが送られて来てしまうので、メールの宛先をGAE(Google App Engine)にして、間引いて画像を保存したり転送するのはどうだろう。
attachmentsにはファイル名とEncodedPayloadが格納されている。
画像ファイル(バイト文字列)にするにはデコードしなければならない。
下記のプログラム例ではメールでJPEG画像を添付して送ると、キャッシュに保存されて /email_view/ファイル名 で見ることが出来ます。
しかし、TS-LCAMはSMTPのポート設定が出来ないようでOP25BのISPではメールが送れないようだ。
attachmentsにはファイル名とEncodedPayloadが格納されている。
画像ファイル(バイト文字列)にするにはデコードしなければならない。
下記のプログラム例ではメールでJPEG画像を添付して送ると、キャッシュに保存されて /email_view/ファイル名 で見ることが出来ます。
しかし、TS-LCAMはSMTPのポート設定が出来ないようでOP25BのISPではメールが送れないようだ。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# email_unpack2.py 2011.2.5
import logging
from google.appengine.api import memcache
from google.appengine.ext import webapp
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
from google.appengine.ext.webapp.util import login_required
from google.appengine.ext.webapp.util import run_wsgi_app
class email_view(webapp.RequestHandler):
@login_required
def get(self, filename):
if filename:
image_data = memcache.get('filename_' + filename)
if image_data:
self.response.headers['Content-Type'] = "image/jpeg"
self.response.out.write(image_data)
return
self.error(404)
class email_unpack(InboundMailHandler):
def receive(self, mail_message):
path = self.request.path
logging.info("path: " + path)
logging.info("Received a message from: " + mail_message.sender)
if hasattr(mail_message, 'attachments'):
for filename, content in mail_message.attachments:
image_data = content.decode()
logging.info("filename: %s, size: %d" % (filename, len(image_data)))
memcache.set('filename_' + filename, image_data, time=60)
application = webapp.WSGIApplication([
('/email_view/(.*)', email_view),
email_unpack.mapping()
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
登録:
投稿 (Atom)



