ในบทความนี้ผมได้ใช้งาน Board จาก Ayarafun/LamLoei Node32s และ Espino32 ซึ่งเป็นของที่ผลิตในไทย มาใช้ในการทดสอบนะครับ
จะอนุมานว่า 1)ติดตั้ง adafruit-ampy และ 2) ทำการ Flash Firmware สำหรับ ESP32 เรียบร้อยแล้วเป้าหมายของในตอนนี้คือให้ทราบการติดตั้ง picoweb ซึ่งเป็น web framework ในภาษา MicroPython
1. เชื่อมต่อกับ Internet
เริ่มต้นการสร้าง function ขึ้นมาเพื่อเชื่อมต่อกับ Router ก่อน
def connect_to_router():
import network
ssid = 'YOUR SSID'
password = 'YOUR SSID PASSWORD'
sta_if = network.WLAN(network.STA_IF)
ap_if = network.WLAN(network.AP_IF)
sta_if.active(True)
ap_if.active(False)
sta_if.connect(ssid,password)
คำอธิบาย
1. เริ่มต้นด้วยการนำ network module เข้ามา2. กำหนดชื่อ SSID และ PASSWORD
3. สร้างตัวแปร sta_if เพื่อเชื่อมกับ wifi module บนบอร์ด ด้วย WLAN ซึ่งเป็น network interface driver ในที่นี้กำหนดให้อยู่ใน mode ของ station หรือ client
4. สร้างตัวแปร ap_if เพื่อเชื่อมกับ wifi module บนบอร์ด ด้วย WLAN ซึ่งเป็น network interface driver ในที่นี้กำหนดให้อยู่ใน mode ของ ap ซึ่งสามารถปล่อยสัญญาณ Wifi ได้
5. ทำการยุติการทำงานใน ap mode และเริ่มต้นการทำงานของ station mode
6. เริ่มการเชื่อมต่อไปยัง Router
ชุดคำสั่งข้างต้นเพียงพอในการทำงานขั้นต้นแล้ว แต่ก็สามารถเพิ่มความสามารถบางอย่างเข้าไปได้อีก เช่น เพิ่มการนับเวลาเข้าไปเพื่อไม่ให้เกิดการรอคอยนานเกินต้องการ พร้อมกับการแจ้งข้อมูล
def connect_to_router():
import network
import time
ssid = 'YOUR SSID'
password = 'YOUR SSID PASSWORD'
counter = 0
sta_if = network.WLAN(network.STA_IF)
ap_if = network.WLAN(network.AP_IF)
sta_if.active(True)
ap_if.active(False)
sta_if.connect(ssid,password)
while not sta_if.isconnected() and counter < 10 :
counter += 1
time.sleep(1)
if sta_if.isconnected() :
print("Connected with {}".format(sta_if.ifconfig()[0]))
else :
print("Connection fail !")
เรียกใช้งาน
>>> connect_to_router()
2. ติดตั้ง picoweb
picoweb เป็น micro web frame เหมือนกับ Flask หรือ Bottle ซึ่งไม่ใช่ full stack web framework แต่ทำงานในสภาพแวดล้อมของ MicroPython (อ้างอิงจากข้อมูลของผู้พัฒนา picoweb ต้องการ RAM Size ขนาด 64K ในตอนเริ่มต้นการใช้งาน ดังนั้นอาจจะใช้งานกับ ESP8266 ไม่ได้) picoweb ต้องการใช้ dependencies สามตัวคือ uasyncio , pkg_resources และ utemplateท่านสามารถทำการติดตั้ง picoweb ได้สองวิธี คือ แบบ Manual คือการทำสำเนา code จากเว็บผู้พัฒนามาวางไว้บนบอร์ดโดยตรง ซึ่งจะต้องทราบโครงสร้างของ package ก็จะออกจะยุ่งยากสักหน่อย และการใช้ utility ชื่อ upip ในบทความจะเลือกใช้ upip ครับ
import upip
upip.install('picoweb')
รอจนการติดตั้งสำเร็จ แล้วสำรวจดูผลของการติดตั้ง
import os
os.listdir()
จะพบว่ามีการสร้าง drirectory ชื่อ lib ขึ้นมา หากเข้าไปดูข้างในก็จะพบ package ที่ถูก download มาคือ uasyncio, logging.py, picoweb และ pkg_resources.py ยังขาดแต่ utemplate ซึ่งเราก็สามารถใช้ upip ได้เช่นกัน
upip.install('utemplate')
ท่านสามารถตรวจสอบ package ที่สามารถติดตั้งด้วย upip ได้จาก https://pypi.python.org/pypi?%3Aaction=search&term=micropython&submit=search
3. ปรับแต่ง picoweb
จากการทดสอบส่วนตัวพบว่า picoweb จะมอง content-type ของไฟล์ที่ส่งมายัง web browser เป็น "text/html" และจะต้องปะ header มาด้วยทุกครั้ง หากเราไม่ได้ใช้การแยกไฟล์ CSS และ Javascript ออกจากตัว HTML file ก็จะไม่มีปัญหา (นอกจากขนาดไฟล์ที่อาจใหญ่เกินไป) แต่หากเราใช้การแยกให้ download แยกกันก็จะเป็นประเด็นและพบ error ขึ้นที่ web browser ครับ หากเข้าไปดูใน source code ของ __init__.py ของ picoweb ในบรรทัดที่ 207 -209 จะเป็นดังนี้
with pkg_resources.resource_stream(self.pkg, fname) as f:
yield from start_response(writer, content_type)
yield from sendstream(writer, f)
ผมได้เติม code เข้าไปดังนี้
types = ["text/javascript","text/css"]
with pkg_resources.resource_stream(self.pkg, fname) as f:
if content_type in types :
await sendstream(writer, f)
else :
yield from start_response(writer, content_type)
yield from sendstream(writer, f)
ทั้งนี้ก็เพื่อไม่ให้ picoweb ทำการปะ header เข้าไปใน javascript และ css ไฟล์ ผลก็ไม่พบ error ปรากฏบน web browser ครับ4. Hello World
มาถึงขั้นตอนการสร้าง Web Server กัน เริ่มต้นด้วยการสร้างแสดง web page ที่มีประโยค "Hello World ! " กันตามธรรมเนียม ก่อนอื่นต้องเข้าใจรูปแบบการสร้างโปรแกรม Web Server ในแบบของ picoweb ก่อน
เริ่มต้นการนำเข้า picoweb module
import picoweb
สร้าง instance ของ WebApp Class โดยส่งค่า __name__ ซึ่งเป็นชื่อของ module
app = picoweb.WebApp(__name__)
ต่อไปเป็นการกำหนด end point ของ request ที่เข้ามา โดยจะใช้ function route() ของ WebApp คอยรับ url ที่เรียกเข้ามาจาก client ผ่าน web browser ในตัวอย่างนี้จะกำหนด url ที่จะทำ route คือ "/" ซึ่งหมายถึง landing page หรือ หรือหน้าแรก เทียบกับวิธีการใน Apache Web Server แล้วก็คือการ route ไปหา index.html นั่นเอง
@app.route("/")
def index(req,res):
pass
เครื่องหมาย @ ข้างหน้า app.route("/") นั้นคือการทำ decoration ในภาษา Python ซึ่งก็คือการขยายการทำงานของ function ให้ไปทางที่ต้องการ ในตัวอย่างนี้เป็นการกำหนดให้มีการทำงานตามชุดคำสั่งใน function index(req,res) เมื่อมี url ที่มีค่า "/" เข้ามาที่ app.rount()จะสังเกตุว่า function index() นั้นต้องการ parameter สองตัวคือ req และ res ตัวแรกเป็น instance ของ Class HTTPRequest และตัวที่สองคือ StreamWriter มีหน้าที่ในการส่งข้อมูลไปยัง client
กิจกรรมภายใน function index() จะมีแค่สองอย่างคือ เตรียมการส่งข้อมูลไปยัง client แล้วทำการส่งข้อมูลออกไป โดยข้อมูลที่ว่าคือ HTML Tag
<h2>Hello World !</h2>
ชุดคำสั่งภายใน function index()
@app.route("/")
def index(req,res):
await picoweb.start_response(res)
await res.awrite("<h2>Hello World !</h2>")
จากชุดคำสั่งข้างบนจะพบว่ามี keyword เพิ่มมาอีกคือ await หากไปเทียบกับตัวอย่างของ picoweb แล้วจะใช้ yield from ซึ่งมีความหมายเหมือนกัน ต่างกันตรงที่ await ใช้กับ Python 3.5 ส่วน yield from ใช้กับรุ่นก่อนหน้า
คำสั่งสุดท้ายในวันนี้คือ app.run() ซึ่งเป็นการสั่งให้ Web Server (ซึ่งอยู่ในตัวแปร app) เริ่มทำงาน
app.run(debug=True, host = "0.0.0.0",port=8080)
ชุดคำสั่งนี้บอกให้ Web Server ทำงาน โดยใช้ IP address ปัจจุบัน (0.0.0.0 แทน IP Address ในขณะนั้น) ที่ port เบอร์ 8080 (default คือ 8081) ที่นี้มาดูชุดคำสั่งเต็ม ๆ
import picoweb
app = picoweb.WebApp(__name__)
@app.route("/")
def index(req,res):
await picoweb.start_response(res)
await res.awrite("<h2>Hello World !</h2>")
app.run(debug=True, host = "0.0.0.0",port=8080)
หลังการเขียนชุดคำสั่งบรรทัดสุดท้ายจบลง ESP32 ก็พร้อมจะทำงานเป็น Web Server แล้ว มาดูที่ Web Browser
สำเร็จ ! ตอนนี้ ESP32 ก็กลายเป็น Web Server ไปแล้วด้วย MicroPython ครับ
ความคิดเห็น
แสดงความคิดเห็น