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)