Raspberry Pi に Python Pyramid のウェブアプリをのせて、ウェブアプリから PWM の設定を行うというアプリをつくる。
まず、Mac 上に Pyramid の環境を作って、そこで動作の確認を行う。
次のインストールは Raspberry Pi 上ではなく、Mac に構築している。
できあがってから、ソースを Raspberry Pi へ移動することにする。
作成するのは、PWM 制御のウェブアプリ。
ウェブでスライダーを表示して、PWM のパルス幅を制御する。
実際に PWM の制御をするのは root 権限が必要なので、ウェブアプリとは別の Python アプリとする。
二つのアプリ間での情報伝達はテキストファイルにする。
まず、Mac 上に Pyramid の環境を作って、そこで動作の確認を行う。
次のインストールは Raspberry Pi 上ではなく、Mac に構築している。
できあがってから、ソースを Raspberry Pi へ移動することにする。
作成するのは、PWM 制御のウェブアプリ。
ウェブでスライダーを表示して、PWM のパルス幅を制御する。
実際に PWM の制御をするのは root 権限が必要なので、ウェブアプリとは別の Python アプリとする。
二つのアプリ間での情報伝達はテキストファイルにする。
- Pyramidのインストール
virtualenvで環境を作って、そこにPyramidをインストールする。
virtualenv と virtualenvwrapper をすでにインストールしてある場合は、3行目の env_pwm をつくるところから。
$ sudo pip install virtualenv $ sudo pip install virtualenvwrapper $ virtualenv --no-site-packages env_pwm $ cd env_pwm $ bin/pip install pyramid
- pwm という名前の Pyramid Project の作成
最終的に、ログインパスワードを入力させてからページを表示したいので、starter ではなく、alchemy とします。
$ bin/pcreate -s alchemy PyPWM
- つくった PyPWM プロジェクトを動かしてみる
setup.py は必要なモジュールを自動的にインストールするので、実行を終了するまで時間がかかる場合があります。
$ cd PyPWM $ ../bin/python setup.py develop $ ../bin/python setup.py test -q $ ../bin/pserve development.ini
ここで、localhost:6543 を見に行くとエラーが表示されています。
こんな感じ。
Pyramid is having a problem using your SQL database. The problem might be caused by one of the following things:
これをやれ、ということで・・・。
$ ../bin/initialize_PyPWM_db development.ini
もう一度・・・。
$ ../bin/pserve development.ini
で、localhost:6543 を見に行くと、今度はちゃんと表示されています。
この段階のプロジェクトを bitbucket にあげておきます。
ついでに wsgi の設定もしてしまいます。
Mac の場合は/etc/apache2/other の modwsgi.conf をこのようにします。
WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On WSGIDaemonProcess pyramid user=snaf group=staff threads=4 \ python-path=/Users/pi/env_pwm/lib/python2.7/site-packages WSGIScriptAlias /pwm /Users/pi/env_pwm/pyramid.wsgi <directory env_pwm="" pi="" sers=""> WSGIProcessGroup pyramid Order allow,deny Allow from all </directory>
/Users/pi/env_pwm/pyramid.wsgi はこう。
from pyramid.paster import get_app, setup_logging ini_path = '/Users/pi/env_pwm/PyPWM/production.ini' setup_logging(ini_path) application = get_app(ini_path, 'main')
これで、Mac 上の localhost/pwm で PyPWM のページが表示されます。
Raspberry Pi の wsgi も設定変更しておきます。
/home/pi/env_pwm/pyramid.wsgi
from pyramid.paster import get_app, setup_logging ini_path = '/home/pi/env_pwm/PyPWM/production.ini' setup_logging(ini_path) application = get_app(ini_path, 'main')
/etc/apache2/mods-available/wsgi.conf の最後の方に追加したもの。
WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On WSGIDaemonProcess pyramid user=pi group=pi threads=4 \ python-path=/home/pi/env_pwm/lib/python2.7/site-packages WSGIScriptAlias /pwm /home/pi/env_pwm/pyramid.wsgi <Directory /home/pi/env_pwm> WSGIProcessGroup pyramid Order allow,deny Allow from all </Directory>
- 忘れずに Raspberry Pi に mercurial をインストールしておく
Mac で作成したプロジェクトを Bitbucket にあげておいて、Raspberry Pi 側でそれを持ってこようと言う考え。hg ではなくて git をお使いの方はそちらをどうぞ。
$ sudo apt-get install mercurial
Raspberry Pi 側では、clone する前に Mac でやったのと同じように Python の仮想環境を作って Pyramid をインストールし、 PyPWM プロジェクトをつくって実行してみる、というところまではやっておく必要があります。
- Mac 上の Eclipse で Pyramid の PyPWM プロジェクトを作成したディレクトリに、同じ名前で Eclipse のプロジェクトを作成
- development.ini の修正
「sqlalchemy.url = sqlite:///...」の上に、これを追加する。
development.ini だけではなく、production.ini にも追加しておく。
# mako template settings mako.directories = pypwm:templates
file log の設定を handlers と logger_root に追加する。handler_filelog も追加する。
[handlers] keys = console, filelog [logger_root] level = INFO handlers = console, filelog [handler_filelog] class = FileHandler args = ('%(here)s/pypwm.log','a') level = NOTSET formatter = generic
古い jQuery を読み込もうとするので、pyramid_debugtoolbar をコメントアウトする。
- pypwm/views.py の修正
念のためにこれを最初に置く。
#!/usr/bin/env python # coding: UTF-8
Mac OS X と Raspberry Pi の切り替えのためにこれを追加する。初期設定ファイルの場所。
import os os_name = os.uname() if os_name[0] == 'Darwin': fname = '/Users/pi/env_pwm/PyPWM/pypwm/pwm.prefs' elif os_name[0] == 'Linux': fname = '/home/pi/env_pwm/PyPWM/pypwm/pwm.prefs'
- pypwm/__init__.py の修正
main() にadd_router と add_renderer を追加する。
add_renderer は、こうすることで、mako テンプレートの拡張子を html とすることができるようになる。
def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.bind = engine config = Configurator(settings=settings) config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') config.add_route('home_org', '/home_org') config.add_route('pypwm', '/pypwm') config.add_route('update_slider_pwm', '/pypwm/update_slider_pwm') config.add_renderer(".html", "pyramid.mako_templating.renderer_factory") config.scan() return config.make_wsgi_app()
- ひとつひとつは大変なので
- py_pwm.py
8 ch 分になっているが、web アプリ側は 1 ch のみ。
#!/usr/bin/env python # coding: UTF-8 """ py_pwm.py RPIO を使うので、py_pwm.py は root 権限で実行する必要がある。 crontab で起動時に立ち上がるように設定しておく。 prefs を 0.1 秒ごとに読んで、更新されていれば、PWM の値をその値で更新する。 prefs が無ければ、0% の出力とする。 prefs は、web アプリ側で作成および書き込みを行う。 prefs の値は ch0 から ch7 までの8つの値を「,」(カンマ)で区切って並べたものとする。 prefs に書き込まれている値は、0から 1999 までの整数値とする。 prefs に書き込まれている値を10倍したマイクロ秒の値がパルス幅となる。 prefs の場所はパラメタで指定する。 @reboot /home/pi/env_pwm/PyPWM/run_as_root/py_pwm.py /home/pi/env_pwm/PyPWM/pypwm/pwm.prefs """ import sys, string, time, os os_name = os.uname() if os_name[0] == 'Darwin': pass elif os_name[0] == 'Linux': if os_name[1] == 'raspberrypi': from RPIO import PWM class PyPwm(): my_debug = False kChNum = 8 kMinVal = 0 kMaxVal = 1999 prefs = 'pwm.prefs' pwm_vals = [] pwm_out = None pwm_init = [ 0, 0, 0, 0, 0, 0, 0, 0] pwm_gpios = [17, 18, 27, 22, 23, 24, 25, 4] pwm_pins = [11, 12, 13, 15, 16, 18, 22, 7] prev_vals = [ 0, 0, 0, 0, 0, 0, 0, 0] def __init__(self, prefs): self.prefs = prefs for ii in range(self.kChNum): init = self.pwm_init[ii] self.pwm_vals.append(init) if os_name[0] == 'Linux': self.pwm_out = PWM.Servo() def read_prefs(self): fd = None try: fd = open(self.prefs, 'r') except IOError: fd = None if fd is not None: line = fd.readline() if self.my_debug: print ("read_prefs: %s" % (line)) items = line.split(',') ii = 0 for item in items: item = string.strip(item) if ii < self.kChNum: try: item = int(item) except ValueError: item = 0 if item < self.kMinVal: item = self.kMinVal if item > self.kMaxVal: item = self.kMaxVal self.pwm_vals[ii] = item ii += 1 def main(self): self.read_prefs() if self.my_debug: for item in self.pwm_vals: print item while True: for ii in range(self.kChNum): gpio = self.pwm_gpios[ii] val = self.pwm_vals[ii] val *= 10 if val != self.prev_vals[ii]: self.prev_vals[ii] = val if self.pwm_out is not None: if val > 0: self.pwm_out.set_servo(gpio, val) if self.my_debug: print "set_servo gpio = %2d, %5d" % (gpio, val) elif val == 0: self.pwm_out.stop_servo(gpio) if self.my_debug: print "stop_servo gpio = %2d" % (gpio) time.sleep(0.1) self.read_prefs() if __name__ == '__main__': argv = sys.argv argc = len(argv) if argc >= 2: fname = argv[1] else: fname = 'pwm.prefs' py_pwm = PyPwm(fname) py_pwm.main()
- ajax_slider_pwm.js
// # coding: UTF-8 // ajax_slider_pwm.js function onchange_slider_pwm() { onchange_slider_sub(1, '#slider_pwm'); } function onchange_slider_sub(channel, slider_id) { var slider_val = jQuery(slider_id).val(); send_option_request(slider_val, channel, 'write'); } function send_option_request(slider_val, channel, command) { // command is 'read' or 'write' $("#id_loading").text("Loading..."); var the_url = "update_slider_pwm"; if (window.location.pathname != "/") { the_url = window.location.pathname + "/" + the_url; } // alert("the_url = " + the_url); $("#id_debug").empty(); $.ajax({ dataType: "json", data: { "pwm_val": slider_val, "channel": channel, "command": command }, cache: true, url: the_url, type: "get", success: function (data, dataType) { // alert("success: " + data); resp_pwm = rcv_response(data); // resp has channel and pwm_val $("#id_loading").empty(); if (command == "read") { var slider_id = "#slider_" + resp_pwm.channel jQuery(slider_id).val(resp_pwm.pwm_val); $("#id_debug").text(resp_pwm.pwm_val) } }, error: function(XMLHttpRequest, textStatus, errorThrown) { $("#id_debug").text("ajax error"); } }); } // function send_option_request(which, key) function rcv_response(jd) { resp_pwm = {pwm_val:jd.pwm, channel:jd.channel, command:jd.command}; return resp_pwm; } // function rcv_option_response()
- index.html
## for maco <!DOCTYPE html> <html> <head> <title>PyPWM</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" href="${request.static_url('pypwm:static/favicon.ico')}" /> <link rel="stylesheet" href="${request.static_url('pypwm:static/jquery/jquery.mobile-1.3.1.min.css')}" /> <link rel="stylesheet" href="${request.static_url('pypwm:static/jquery/slider.css')}" /> <script src="${request.static_url('pypwm:static/jquery/ajax_slider_pwm.js')}"></script> <script src="${request.static_url('pypwm:static/jquery/jquery-1.9.1.min.js')}"></script> <script src="${request.static_url('pypwm:static/jquery/jquery.mobile-1.3.1.min.js')}"></script> <style type="text/css"></style> </head> <body> <form action="${request.route_url('home')}" method="post"> <div id="slider"> <label for="slider_pwm">PWM:</label> <input type="range" name="slider_pwm" id="slider_pwm" value="${pwm_dict['pwm_val']}" min="0" max="1999" step="1" onchange="onchange_slider_pwm()" /> </div> </form> <div id="id_loading"></div> <div id="id_debug"></div> </body> </html>
- __init__.py
from pyramid.config import Configurator from sqlalchemy import engine_from_config from .models import ( DBSession, Base, ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.bind = engine config = Configurator(settings=settings) config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') config.add_route('home_org', '/home_org') config.add_route('update_slider_pwm', '/update_slider_pwm') config.add_renderer(".html", "pyramid.mako_templating.renderer_factory") config.scan() return config.make_wsgi_app()
- view.py
#!/usr/bin/env python # coding: UTF-8 from pyramid.response import Response from pyramid.view import view_config from sqlalchemy.exc import DBAPIError from .models import ( DBSession, MyModel, ) import time, string, os os_name = os.uname() if os_name[0] == 'Darwin': fname = '/Users/pi/env_pwm/PyPWM/pypwm/pwm.prefs' elif os_name[0] == 'Linux': fname = '/home/pi/env_pwm/PyPWM/pypwm/pwm.prefs' @view_config(route_name='home_org', renderer='templates/mytemplate.pt') def my_view(request): try: one = DBSession.query(MyModel).filter(MyModel.name == 'one').first() except DBAPIError: return Response(conn_err_msg, content_type='text/plain', status_int=500) return {'one': one, 'project': 'PyPWM'} conn_err_msg = """\ Pyramid is having a problem using your SQL database. The problem might be caused by one of the following things: 1. You may need to run the "initialize_PyPWM_db" script to initialize your database tables. Check your virtual environment's "bin" directory for this script and try to run it. 2. Your database server may not be running. Check that the database server referred to by the "sqlalchemy.url" setting in your "development.ini" file is running. After you fix the problem, please restart the Pyramid application to try it again. """ #---- pwm @view_config(route_name='home', renderer='index.html') def home(request): pwm_dict = {} pwm_val = read_prefs() pwm_dict['pwm_val'] = pwm_val return dict(pwm_dict=pwm_dict) @view_config(route_name='update_slider_pwm', xhr=True, renderer='json') def update_slider_pwm(request): """ This function is call from ajax_slider_pwm.js send_option_request when slider is updated. receive json pwm data by ajax "pwm_val": slider_val, "channel": channel, "command": command command is 'read' or 'write' """ pwm_val = request.GET.get('pwm_val') pwm_val = to_int(pwm_val) channel = request.GET.get('channel') channel = to_int(channel) command = request.GET.get('command') if command == 'read': pwm_val = read_prefs() elif command == 'write': write_prefs(pwm_val) return { 'pwm_val': pwm_val, 'channel': channel, 'command': command, } def read_prefs(): kMinVal = 0 kMaxVal = 1999 pwm_val = 0 fd = None try: fd = open(fname, 'r') except IOError: fd = None if fd is not None: line = fd.readline() pwm_val = string.strip(line) try: pwm_val = int(pwm_val) except ValueError: pwm_val = 0 if pwm_val < kMinVal: pwm_val = kMinVal if pwm_val > kMaxVal: pwm_val = kMaxVal fd.close() return pwm_val def write_prefs(pwm_val): my_error_count = 0 fin = False while (not fin): try: fd = open(fname, 'w') except IOError: fd = None if fd is not None: fd.write(str(pwm_val)) fd.close() fin = True else: if my_error_count < 10: my_error_count += 1 time.sleep(0.1) else: fin = True def to_int(the_str): try: int_value = int(the_str) except: int_value = 0 return int_value
beğeni satın al
返信削除smm panel
返信削除smm panel
iş ilanları
İnstagram takipçi satın al
hırdavatçı
beyazesyateknikservisi.com.tr
servis
tiktok jeton hilesi