ESP32_Rotate_多線程.py 這個程式的主要功能是使用 ESP32-CAM 建立一個包含即時影像擷取功能的網頁伺服器。程式首先連接至 Wi-Fi,初始化相機,然後啟動一個 Web 伺服器,允許使用者透過網頁控制相機拍攝並顯示圖片。
以下是詳細的程式碼說明與建議:
Wi-Fi 連接設定:
透過 SSID 和 PASSWORD 變數配置 Wi-Fi 網路。
在 connect_to_wifi 函數中嘗試連接網路,並檢查連接狀態。
相機初始化:
init_camera 函數用於初始化相機設定,如果初始化失敗將會重試,每次重試間隔時間加倍。
Web 伺服器建立:
web_server 函數建立一個非阻塞的伺服器,處理來自客戶端的連接和請求。
利用 select 來非阻塞地檢查哪些 socket 是可讀狀態,並相應地處理。
處理網頁請求:
handle_connection 函數處理每個客戶端的 HTTP 請求,根據請求路徑返回相應的 HTML 頁面或圖片。
send_image 負責擷取圖片並回應給客戶端。
send_html 負責發送包含 HTML 和 JavaScript 的頁面,使得用戶可以控制影像的旋轉並每0.2秒更新一次圖片。
垃圾回收:
在 web_server 的無限迴圈中定期呼叫 gc.collect(),以釋放未使用的記憶體。
異常處理:在連接 Wi-Fi 和相機初始化過程中加強異常處理,確保任何錯誤都能被適當地記錄和處理。
安全性:Wi-Fi 密碼和其他敏感信息應該避免硬編碼在程式中。考慮使用環境變數或配置文件來管理這些敏感資料。
程式碼重構:將 HTML 和其他常數字符串移至外部文件或獨立的模塊,以提高代碼的可讀性和可維護性。
伺服器效能:為了提高伺服器效能,考慮使用更高效的非阻塞或異步庫,例如 asyncio,來處理網路連接和數據傳輸。
這段程式碼提供了一個基礎架構,展示了如何使用 ESP32-CAM 進行網絡編程和即時影像處理,是物聯網項目和相機控制應用的實用例子。
4
你說:
還有為程式在程序上加上功能註解
ChatGPT 說:
ChatGPT
這裡我為您的程式加上功能註解,讓其功能和運作流程更清楚易懂:
python
複製程式碼
# 20241022
import machine
import network
import socket
import select
import camera
import time
import gc
# Wi-Fi 配置變數
SSID = 'Bili-Net'
PASSWORD = '0932388283'
# 初始化相機的函數
def init_camera():
retry = 10 # 最多重試10次
delay = 1 # 初始延遲為1秒
while retry > 0:
try:
camera.init(0, format=camera.JPEG) # 初始化相機設置
camera.framesize(camera.FRAME_QVGA) # 設定相機的畫面大小
camera.quality(10) # 設定相機的畫質
print("相機初始化成功!")
return
except Exception as e:
print("相機初始化失敗,重試中...", e)
time.sleep(delay)
retry -= 1
delay *= 2 # 延遲時間翻倍
raise Exception("相機初始化最終失敗")
# 連接到Wi-Fi的函數
def connect_to_wifi():
station = network.WLAN(network.STA_IF)
station.active(True) # 啟動無線網路介面
station.connect(SSID, PASSWORD) # 連接到Wi-Fi
for i in range(10): # 嘗試10次,每次等待1秒
if station.isconnected():
break
time.sleep(1)
else:
print("Failed to connect to Wi-Fi.")
return None
print('Connected to Wi-Fi.')
print('Network config:', station.ifconfig()) # 顯示網路配置
return station
# 定義Web Server的函數
def web_server(station):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setblocking(0) # 設置socket為非阻塞模式
s.bind(('', 80)) # 綁定到80端口
s.listen(5) # 開始監聽連接
print('Web server running on http://{}'.format(station.ifconfig()[0]))
socket_list = [s]
try:
while True:
gc.collect() # 垃圾回收
readable, _, _ = select.select(socket_list, [], [], 5)
for sock in readable:
if sock is s:
conn, addr = s.accept() # 接受連接
conn.setblocking(0) # 設置連接為非阻塞模式
socket_list.append(conn)
print('Got a connection from %s' % str(addr))
else:
handle_connection(sock, socket_list)
finally:
s.close()
def handle_connection(conn, socket_list):
conn.settimeout(10) # 設置超時時間
try:
request = conn.recv(1024).decode('utf-8') # 接收請求
if '/capture' in request:
send_image(conn) # 發送影像
else:
send_html(conn) # 發送HTML頁面
except OSError as e:
print('Connection closed: OSError', e)
finally:
conn.close()
if conn in socket_list:
socket_list.remove(conn)
def send_image(conn):
photo = camera.capture() # 擷取相機影像
if photo:
conn.sendall(b'HTTP/1.1 200 OK\r\n')
conn.sendall(b'Content-Type: image/jpeg\r\n')
conn.sendall(b'Connection: close\r\n\r\n')
for i in range(0, len(photo), 1024):
conn.sendall(photo[i:i+1024]) # 分段發送影像資料
else:
conn.sendall(b'HTTP/1.1 404 Not Found\r\n')
conn.sendall(b'Connection: close\r\n\r\n')
print("Failed to capture image")
def send_html(conn):
# HTML 內容
html = """
<!DOCTYPE html>
<html>
<head>
<title>ESP32-CAM Rotate Image</title>
</head>
<body>
<header>ESP32 即時攝影 - 旋轉控制</header>
<div id="button-container">
<button onclick="rotateImage()">Rotate</button>
</div>
<div id="image-container">
<img src="/capture?time=0" id="cam-image">
</div>
<script>
function rotateImage() {
var img = document.getElementById('cam-image');
img.style.transform = 'rotate(90deg)';
}
</script>
</body>
</html>
"""
conn.sendall(b'HTTP/1.1 200 OK\r\n')
conn.sendall(b'Content-Type: text/html; charset=utf-8\r\n')
conn.sendall(b'Connection: close\r\n\r\n')
conn.sendall(html.encode('utf-8'))
# 主程序
def main():
station = connect_to_wifi()
if station:
init_camera()
web_server(station)
if __name__ == '__main__':
main()
這些註解幫助釐清了每個函數的功能和程序的主要步驟,同時也指出了重要的程序流程和決策點。希望這樣的註解有助於更好地理解和維護程式碼。