ラズパイにwebからアクセスして、GPIOの状況を見たり設定したいとする。
多くの人がwebiopiに走るようだ。
しかし、このパッケージは使わないことにした。
理由はwebiopiは便利にできていて、webサーバーを兼ねてくれている。
自分でページを作ったり、そこにjavascriptを動かそうとすると、結構、調べなければならない。
しかも開発は7年前に止まっている。
いろいろ考えたが、webサーバーを動かしてCGIをpythonで書くということにする。CGIは別にPearlやPHPだけがつながるわけじゃない。Common Gateway Interfaceで様々な言語環境でプログラムを書いてかまわない。
軽量ウェブサーバーの導入
sudo apt install lighttpd
軽量なだけに、不要なモジュールは最初は動いていない。
状況は
sudo lighttpd-enable-mod
で調べられる。
動かしたいモジュールを
sudo lighttpd-enable-mod cgi
とする。
設定を反映し、スタートする。
sudo sytemctl restart lighttpd
起動したらlighthttpdを動かしたいので、
systemctl enable lighttopd.service
(やめたい時は、systemctl disable lighttpd.service)
設定ファイルは/etc/lighttpd/lighttpd.conf
なかにserver.document-rootがあるので適当に自分がドキュメントルートを起きたいフォルダーを指定。
cgiでpythonを起動させるには/etc/lighttpd/conf-availabe/10-cgi.confを設定する。
中を読めばわかるけど、
$HTTP["url"]=~ "^/cgi-bin/"{
cgi.assign = ( ".py" => "/usr/bin/python" ) alias.url += ("/cgi-bin" => "usr/...../cgi-bin/") }
とか設定する。
ここでpythonの実行ファイル、/cgi-bin/とブラウザーから要求された時の真のフォルダー名を設定する。つまりhtml内に/cgi-bin/と書くが、その本当の場所はここで決まる。
普通、CGIはドキュメントルート下のサブフォルダーCGI-binとする。
ドキュメントルートに以下のhtmlをindex.htmlとして置いてみた。
<!DOCTYPE html><html><head>
<meta charset="utf-8">
<title>index</title></head><body>
<form action="/cgi-bin/formtest1.py" method="post">
<input type="text" name="value1"><BR />
<input type="text" name="value2"><BR />
<input type="submit" name="submit">
</form>
</body>
</html>
cgiプログラムはformtest1.py
#!/usr/bin/python3
import cgi
import cgitb # for debug
cgitb.enable() # for debug
form = cgi.FieldStorage() # get data from form
value1 = form.getvalue('value1','')
value2 = form.getvalue('value2','')
print('Content-Type: text/html; charset=UTF-8\n')
html_body = '''
<!DOCTYPE html>
<html>
<body>
<h1>python cgi test</h1>
<p>value1 is %s</p>
<p>value2 is = %s</p>
</body>
</html>
'''
print(html_body % (value1, value2))
pythonからGPIOを動かすためには、ROS2を使ってみる(1)で書いたpigpioの設定をする。
LEDを繋いだ。
CGIでGPIOをオンオフするサンプルHTML。チェックボックスをビジュアルにしているので長い。
Javascriptを入れてみたかったのだ。あしからず。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewpoint" content="width=device-width, initial-scale=1.0" />
<title>switch</title>
<style type="text/css">
<!--
.switch_label {
display: flex;
align-items: center;
}
input[type="checkbox"]{
position:absolute;
width: 0;
height: 0;
}
.base {
width: 56px;
border-radius: 16px;
height: 32px;
background-color: #ddd;
}
input:checked ~ .base{
background-color: rgb(219,234,254);
transition: 0.5s;
}
.title {
margin-left: 4px;
}
.circle {
position: absolute;
top: 4px;
left: 4px;
width: 24px;
height: 24px;
border-radius: 12px;
background-color: gray;
}
input:checked ~ .circle {
transform: translateX(100%);
backgound-color: blue;
}
.switch {
position: relative;
}
-->
</style>
<script>
const checkbox = document.getElementById('switch');
checkbox.addEventListener('click', () => {
const title = document.querySelector('.title');
title.textContent = checkbox.checked ? 'ON' : 'OFF' ;});
</script>
</head>
<body>
<h1>switch button</h1>
<form action="/cgi-bin/formcgi3.py" method="POST">
<label for="switch" class="switch_label">
<div class="switch">
<input type="checkbox" id="switch" name="onoff" />
<div class="circle"></div>
<div class="base"></div>
</div>
<span class="title">Off</span>
</label>
<input type="submit" vaalue="GO">
</form>
</body>
</html>
CGI(formcgi3.py)は以下のとおり
#!usr/bin/python3
import cgi
import cgitb
import pigpio
cgitb.enable()
pi = pigpio.pi()
pi.set_mode(21, pigpio.OUTPUT)
form = cgi.FieldStorage()
if (form.getvalue('onoff') ):
pi.write(21, 1)
else:
pi.write(21, 0)
print("Content-Type: text/html")
print()
htmlTxt = '''
<h1 > Done < /h1 >
'''
print(htmlTxt)
一応、動作は確認できた。