WEBアプリでラズパイ操作(Flask, Python)

PCでキー操作して、ラズパイでpythonコードを実行する

STEP1. キー操作画面はWEBサーバー(2)で配信して、同じネットワークにあるPCがキー操作をする。
STEP2. キー操作に対応するpythonアプリ(3)を呼び出してラズパイのpythonコードを実行する。
STEP3. pythonコードの実行結果はアプリサーバー(4)を介して、(2)のWEBサーバーのHTMLファイルでPCに伝達します。

(2)WEBサーバー

ラズパイでWEBサーバーが動いていることを検査します

WEBサーバー(Apache2)のステータスを systemctl コマンドで表示します。

$ sudo systemctl status apache2

Active: の項目が 「active (running)」になっていれば正常。もしapache2がインストールされていなければ「ラズパイでWEBサーバーを立ち上げる」を実行します。

ラズパイと同じネットワークに接続されているPCからWEBブラウザでアクセスして動作確認もできます。
WEBブラウザのURLは、ラズパイのホスト名を指定するか、IPアドレスを指定します。例 http://razpi10.local/

JavaScript が動くことを検査します

ラズパイのディレクトリやファイルは悪意ある改ざんがされないように適切なアクセス制御がされています。通常ユーザー「pi」でHTMLファイルを編集できるように chmod コマンドで設定します。
ディレクトリ「/var/www」に対して、[o]他のユーザーに[w]書き込み権限を[+]追加するという意味です。

$ sudo chmod –R o+w /var/www

ユーザー:[u]ユーザー/所有者, [g]グループ, [o]その他ユーザー, [a]全てのユーザー
演算子:[+]追加, [-]削除, [=]指定する
アクセス権:[r]読み込み, [w]書き込み, [x]実行
指定したパターンに一致するディレクトリとすべてのファイルモードを変更する:[-R]

JavaScript コードをindex.htmlファイルに追加します

ディレクトリを移動して、ファイル[index.html]を編集する

$ cd /var/www/html
$ sudo nano index.html

<body>タグ内に次のコードを追加します。これはWEBページを1秒毎に再表示して、hoge というタグの場所に現在の日付と時刻を表示するコードのサンプルです。hogeは好きな名前に変更できます。

<div id="hoge"></div>
<script>
setInterval( function() {
  document.getElementById("hoge").innerHTML = new Date().toLocaleString();
}, 1000);
</script>

エディタ nano で[書き込み]と[終了]をして、PCのWEBブラウザでWEBページ<例 http://razpi10.local/>を検査します。
1秒毎に[YYYY/MM/DD hh:mm:ss]の形式で表示が更新されていれば JavaScript が動作しています。

ここまででWEBサーバー(2)の部分の動作確認ができました

続いてWEBブラウザからラズパイの python アプリを実行できるように準備します
制作する pythonアプリ は、ラズパイのGPIOに接続したLEDを、PCのWEBブラウザでON/OFFするもの。
これができれば、ラズタンクの左右モーターも前進・後進できるはず。

(3)サーバー側 pythonアプリ

LEDの配線

ラズパイのGPIOは空いている端子を選んでください。
下図例はGPIO26を使います。後述する python コードは、GPIO番号を一致させることを忘れずに。
LEDの+側に抵抗を入れるのも忘れずに。GPIO出力は 3.3V 最大電流50mAですが、LED赤のパーツ番号は不明ですが30mA程度の部品があるようなので、この場合、LED赤が壊れます。

LinuxコマンドだけでLEDを点灯する

次の3ステップでLEDをON/OFFします。この仕組みの詳しい説明は「歩行者用信号機をシミュレーション」で紹介しています。

LEDを接続したGPIOを指定する(GPIO26を使う)

$ echo 26 > /sys/class/gpio/export

使うGPIOの入出力を設定する。今回は出力(out)です。

$ echo out > /sys/class/gpio/gpio26/direction

LEDを点灯する

$ echo 1 > /sys/class/gpio/gpio26/value

LEDを消灯する

$ echo 0 > /sys/class/gpio/gpio26/value

Python フレームワーク(Flask)をインストール

PythonアプリをWEBアプリとして、WEBサーバー(Apache2)で動かすには「mod_wsgi」モジュールが必要です

$ sudo apt-get install libapache2-mod-wsgi-py3

Pythonフレームワーク(Flask)をインストールします

$ sudo pip3 install Flask

ラズパイを再起動します

$ sudo reboot

WEBアプリを構築します

3つのファイルを2つのディレクトリに新規作成します。

ラズパイで動かす pythonアプリ 「app.py」を作成

新規ディレクトリ「/var/www/flask」を作って、新規ファイル「app.py」を作ります。

$ cd /var/www
$ sudo mkdir flask
$ cd flask
$ nano app.py

「app.py」のコード

#!/usr/bin/ python3
# -*- coding: utf-8 -*-
import subprocess

# Flaskフレームワークのインポート
from flask import Flask
# テンプレートエンジンのインポート
from flask import render_template

# Flaskインスタンスの作成
app = Flask(__name__)

# ルーティング
@app.route('/')
def index():
    # GPIO26を出力に初期設定する
    subprocess.run('echo 26 > /sys/class/gpio/export', shell=True)
    subprocess.run('echo out > /sys/class/gpio/gpio26/direction', shell=True)
    print('GPIOを初期化しました')
    return render_template('ledapp.html')

# LEDをONする。URIコマンド「ledOn」を指定するとsubprocessでLinuxコマンドを実行する
@app.route('/ledOn')
def ledON():
    subprocess.run('echo 1 > /sys/class/gpio/gpio26/value', shell=True)
    return '<p>LED ON</p>'

# LEDをOFFする。URIコマンド「ledOff」を指定するとsubprocessでLinuxコマンドを実行する
@app.route('/ledOff')
def ledOFF():
    subprocess.run('echo 0 > /sys/class/gpio/gpio26/value', shell=True)
    return '<p>LED OFF</p>'

# アプリ起動時のWEBポートを初期設定
# hostのIPアドレス0.0.0.0は、自分のラズパイ localhost を意味します
# ポート番号が5002。PCからこのポート番号でアクセスします。
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5002)

python アプリの動作確認

ラズパイと同じネットワークにあるPCからWEBブラウザのURIを指定してWEBアプリを実行します。
(参考)
URL:「Uniform Resource Locator」の略で、WEBの場所を示す
URI:「Uniform Resource Identifier」の略で、WEBのファイルを識別する

まずはラズパイ側で pythonアプリ「app.py」を起動する

$ cd /var/www/flask
$ sudo python app.py

次にPCのWEBブラウザでURIを指定する。
最初はGPIOの初期化から。URLはホスト名:ポート番号とURIの組み合わせ。

http://razpi10.local:5002/

LEDをONする

http://razpi10.local:5002/ledOn

LEDをOFFする

http://razpi10.local:5002/ledOff

ここであらためて「app.py」のコードを眺めて 「/」 「/ledOn」 「/ledOff」 を確認してください。改造するときはこのコードを変更すればよいか分かりますか?

PCのWEBブラウザで動かす「ledapp.html」を作成

新規ディレクトリ「/var/www/flask/template」を作り、新規ファイル「ledapp.html」を作ります。

$ cd /var/www/flask
$ sudo mkdir templates
$ cd templates
$ nano ledapp.html

「ledapp.html」のコード

<html>
  <body>
    <h1>ラズパイ(Razpi10.local) 操作メニュー</h1>
    <p>[E]キーでLEDをON/OFFします</p>
    <p id="output"></p>
    <p id="comment"></p>

<script>
let ledStatus = 0;
document.addEventListener('keypress', keypress_ivent);
document.addEventListener('keyup', keyup_ivent);

// キーが押された時
function keypress_ivent(e) {
        // id "output" の場所に e の値を入れます
        document.getElementById('output').innerHTML = e.key;
        // もし e の値が[e]ならば
        if (e.key == 'e') {
                // ラズパイの WEB API を呼び出すオブジェクトxhrを作る
                var xhr = new XMLHttpRequest();
                // LED点灯をON/OFF繰り返すため、LED変数が0ならON(1)にして、1ならOFF(0)にする
                if (ledStatus == 0) {
                        // xhrオブジェクトにメソッド(LED ON 命令)を指定する
                        xhr.open('GET', '/ledOn');
                        ledStatus = 1;
                } else {
                        xhr.open('GET', '/ledOff');
                        ledStatus = 0;
                }
                // WEB API リクエストの応答があったらここを実行する. とxhrオブジェクトに指定する
                xhr.onreadystatechange = function() {
                        // 応答 readyStat=[1:呼び出し済み 2:ヘッダ情報を読める 3:ダウロード中 4:操作完了]
                        // 応答 status=[2xx:成功, 3xx:リダイレクト, 4xx:クライアントエラー, 5xx:サーバーエラー]
                        if (xhr.readyState == 4 && xhr.status == 200) {
                                document.getElementById('comment').innerHTML = xhr.responseText;
                        }
                }
                // WEB API のリクエストを送信する
                xhr.send();
        }
        return false;
}

// キーが離された時、画面表示をクリアする
function keyup_ivent(e) {
        document.getElementById('output').innerHTML = '';
        document.getElementById('comment').innerHTML = '';
        return false;
}
</script>

  </body>
</html>

(4)WEBアプリを構築します

WEBサーバー(Apache2)と Pythonアプリを接続してWEBアプリを構築します。WSGI(Web Server Gateway Interface, 通称ウィスキー)ファイルを新規作成します。

$ cd /var/www/flask
$ sudo nano app.wsgi

「app.wsgi」のコード

#!/usr/bin/ python3
# -*- coding:utf-8 -*-
import sys

# パスの指定
sys.path.insert(0, '/var/www/flask')
from app import app
application = app

ラズパイ側でWEBアプリを起動します。

$ sudo python app.py

 * Serving Flask app "app" (lazy loading)
 * Environment: production
 * Debug mode: off
 * Running on http://0.0.0.0:5002/ (Press CTRL+C to quit)

PC側でWEBアプリを呼び出します。

WEBブラウザを立ち上げて、URLを指定します

http://razpi10.local:5002/

表示される画面

Razpi10.local 操作メニュー
[E]キーを押してLEDをON/OFFします

PCの[E]キーを押すと、ラズパイのLEDが点灯・消灯を繰り返します。押し続けるとキーバッファされて点滅します。

まとめ

ラズパイのWEBサーバー・WEBアプリと、PCのWEBブラウザでキー操作できるようになりました。これをクライアント・サーバー型アプリといいます。今回は練習のためLED点灯だけにしましたが、ラズタンクのモーターを制御するWEBアプリに挑戦しましょう。2023年はCUI(テキスト)だけの操作だったのでGUI(グラフィカル)な操作パネルを作ってみたいです。音波センサーで前方までの距離をグラフ表示したり、サーボモーターの角度をグラフィック表示したりできたらいいのになー。


コメントを残す