การสร้าง HTTP Server (Python 2)
ส่วนทีี่ 1 : Libraries
from gadgets.motors.servos import Servo5V
from BaseHTTPServer import BaseHTTPRequestHandler
import cgi
import time
import atexit
from os import curdir, sep
from urlparse import urlparse
บรรทัดทีี่ 1 : นำเข้า library จาก RPI.GPIO.TH เพื่อใช้ในการควบคุม Servo ชนิดใช้แรงดันไฟฟ้า 5 V
บรรทัดที่ 2 : นำ BaseHTTPRequestHandler เข้ามาเพื่อใช้ในการจัดการความต้องการที่ส่งมาจาก client มายัง Raspberry Pi
บรรทัดที่ 3 : cgi เป็น library ที่ช่วยให้เราแยกข้อมูลที่ส่งมาจาก client ด้วยวิธี POST ออกเป็นส่วน ๆ
บรรทัดที่ 5 : atexit นำเข้ามาเพื่อช่วยในการ clean up การใช้งาน GPIO
บรรทัดที่ 6 : curdir, sep ช่วยในการจัดทำ path ของ static file ให้ถูกต้อง
บรรทัดที่ 7 : urlparse เช่นเดียวกับ cgi แต่ใช้ในกรณีที่ทาง client ส่งข้อมูลมาด้วยวิธี GET
ส่วนที่ 2 : Request Handler Class
สร้าง Request Handler Class ซึ่งจะเป็นตัวทำหน้าที่หลักในการจัดการกับข้อมูล (HTTP requests) ที่ส่งมายัง HTTP Server โดยเราจะเริ่มต้นด้วยการ overwrite 2 methods คือ do_GET และ do_POST โดยยังมี code ภายใน
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
return
def do_POST(self):
return
โดยทั่วไปเราเข้าใจกันแล้วว่าหน้าแรกที่เราได้เห็นสำหรับเว็บไซต์ทั่วไปมักมีชื่อว่า index.html ซึ่งเราจะสร้างไว้เป็น static file แยกไว้ต่างหาก เมื่อ client ส่งความต้องการมาด้วยรูปแบบของ URL ที่ปิดท้ายด้วยสัญญลักษณ์ "/" จะถูกตีความว่าให้ส่งเนื้อหาใน index.html ไปยัง browser
def do_GET(self):
query_str = urlparse(self.path)
if query_str.path == '/':
self.path = './index.html'
with open(curdir + sep + self.path) as f:
self.send_response(200)
self.send_header('Content-type',"text/html")
self.end_headers()
self.wfile.write(f.read())
return
Code ที่เพิ่มเข้าไปใน do_GET เริ่มต้นด้วยการแยก request ออกด้วยคำสั่ง urlparse(self.path) ซึ่งทำให้เราทราบว่ามี query string เป็นอย่างไร ในกรณีที่ query string เป็น "/" ก็จะทำการ อ่านข้อมูลจาก index.html ขึ้นมาไว้ใน self.wfile (ที่สำหรับเขียนข้อมูลของ BaseHTTPRequestHandler ก่อนส่งออกไปยัง client) สำหรับเนื้อหาใน index.html เป็นดังนี้
บนหน้าจอของ browser จะแสดงให้เป็น slider ที่แสดงค่าตั้งแต่ 0 - 180 ซึ่งตรงกับค่าช่วงกว้างของ Servo นั่นเอง ค่าของ slider จะถูกส่งไปยัง function write_servo(angle) เพื่อทำการส่งค่ามุมกลับไปยัง HTTP Server ด้วยวิธีการ POST (หรือการ submit form ในกรณีที่ใช้ form บนเว็บเพจ)
ขั้นตอนต่อไปเป็นการเพิ่ม code เข้าไปใน do_POST ที่วางไว้ในตอนแรก ดังนี้
def do_POST(self):
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
})
servo.write(int(form["write_servo"].value))
self.send_response(200)
self.send_header('Content-type','text/plain')
self.end_headers()
self.wfile.write(form["write_servo"].value)
return
ข้อมูลที่ผ่านการ submit form หรือการส่งด้วยวิธี POST เราจะทำการ dump ออกมาเก็บไว้ในตัวแปร form ซึ่งเป็น instance ของ cgi.FieldStorage class ก่อนแล้วจึงจะสามารถนำค่าที่เก็บไว้มาใช้งานได้ โดยค่าทีีส่งมานั้นเก็บไว้ใน key ชืี่อ 'write_servo' (ดูใน index.html) ซึ่งจะถูกส่งต่อไปให้ servo ใช้งานต่อไปส่วนที่ 3
def cleanup():
servo.cleanup()
if __name__ == '__main__':
from BaseHTTPServer import HTTPServer
global servo
servo = Servo5V(pin_number=12,freq=100)
atexit.register(cleanup)
server = HTTPServer(('', 8080), RequestHandler)
print ('Starting server, use to stop')
server.serve_forever()
งานที่เหลือได้แก่ การ cleanup GPIO หลังการใช้งาน และการประกาศตัวแปรที่จำเป็น ได้แก่
servo = Servo5V()
เพื่อใช้ควบคุม Server ผ่าน GPIO
server = HTTPServer(('', 8080), RequestHandler)
เพื่อใช้เป็น HTTP Server ที่ให้บริการผ่าน port 8080
ฉบับสมบูรณ์
RaspiHTTPServer.py :
from gadgets.motors.servos import Servo5V
from BaseHTTPServer import BaseHTTPRequestHandler
import cgi
import time
import atexit
from os import curdir, sep
import os
from urlparse import urlparse
class RequestHandler(BaseHTTPRequestHandler):
def get_mimetype(self):
if self.path.endswith(".html"):
mimetype='text/html'
if self.path.endswith(".jpg"):
mimetype='image/jpg'
if self.path.endswith(".gif"):
mimetype='image/gif'
if self.path.endswith(".js"):
mimetype='application/javascript'
if self.path.endswith(".css"):
mimetype='text/css'
return mimetype
def response_static_file(self):
with open(curdir + sep + self.path) as f:
mimetype = self.get_mimetype()
self.send_response(200)
self.send_header('Content-type',mimetype)
self.end_headers()
self.wfile.write(f.read())
def do_GET(self):
query_str = urlparse(self.path)
if query_str.path == '/':
self.path = './index.html'
with open(curdir + sep + self.path) as f:
mimetype = self.get_mimetype()
self.send_response(200)
self.send_header('Content-type',mimetype)
self.end_headers()
self.wfile.write(f.read())
return
def do_POST(self):
#dump POST request onto variable
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
})
servo.write(int(form["write_servo"].value))
self.send_response(200)
self.send_header('Content-type','text/plain')
self.end_headers()
self.wfile.write(form["write_servo"].value)
return
def cleanup():
servo.cleanup()
if __name__ == '__main__':
from BaseHTTPServer import HTTPServer
global servo
servo = Servo5V(pin_number=12,freq=100)
atexit.register(cleanup)
server = HTTPServer(('', 8080), RequestHandler)
print ('Starting server, use to stop')
server.serve_forever()
ผลการทำงาน
$ python RaspiHTTPServer.py
แล้วเปิดเว็บบราวเซอร์ด้วย URL : http://[your Raspberry Pi address]:8080/
Sign up here with your email
ConversionConversion EmoticonEmoticon