本文將改寫Python Flask網站伺服器檔案上傳程式,設置一個新路由“/esp32cam”,接收ESP32CAM微電腦控制板上傳的影像檔,並且將影像檔用上傳的日期與時間重新命名儲存。
處理上傳檔案的程式碼,之前是寫在首頁’/路由的’upload_file()函式,像這樣:
新增處理ESP32CAM控制板上傳影像的程式,跟之前處理網頁上傳檔案的程式,基本上是一樣的,所以筆者把處理上傳檔案的程式碼放在另一個“handle_file”自訂函式。
handle_file()函式接收一個request(請求)物件,然後依照上傳檔的處理情況,傳回「字典」型態的資料,其中的“msg”包含狀態訊息,若上傳檔案處理成功,msg成員的值將是“ok”,而filename成員的值將是上傳檔的名字。
改成呼叫handle_file()函式處理上傳檔的“/”路由程式碼如下:
用當前的日期時間設定上傳檔名
為了避免檔名重複,handle_file()自訂函式會將每個上傳檔的名字改成當前的日期和時間。datetime模組的datetime.now()函式可傳回當前的日期與時間,透過str()函式將它轉成字串;因為Windows系統的檔名不可包含“:”字元,因此最後透過字串物件的replace()方法,把字串裡的所有“:”都替換成“_”。
處理上傳檔案的handle_file函式
底下是handle_file()函式的程式碼,唯有檔案上傳成功,它才會傳回檔名。
def handle_file(request): if 'filename' not in request.files: return {"msg": 'no_file'} # 傳回代表「沒有檔案」的訊息 file = request.files['filename'] # 取得上傳檔 if file.filename == '': return {"msg": 'empty'} # 傳回代表「空白」的訊息 if file: file_type = filetype.guess_extension(file) # 判斷上傳檔的類型 if file_type in ALLOWED_EXTENSIONS: file.stream.seek(0) # filename = secure_filename(file.filename) # 重新設定檔名:日期時間 + ‘.’ + ‘副檔名’ filename = str(datetime.datetime.now()).replace( ':', '_') + '.' + file_type file.save(os.path.join( app.config['UPLOAD_FOLDER'], filename)) # 傳回代表上傳成功的訊息以及檔名。 return {"msg": 'ok', "filename": filename} else: return {"msg": 'type_error'} # 傳回代表「檔案類型錯誤」的訊息
處理ESP32CAM控制板上傳檔案的路由
處理ESP32CAM上傳檔案的“/esp32cam”路由程式,只需把連線請求轉給handle_file()函式,再把函式傳回的訊息發送給用戶端(ESP32CAM開發板)。
修改之後的完整Python Flask網站伺服器程式碼(app.py檔)如下:
import datetime import os import pathlib import filetype from flask import Flask, flash, request, redirect, url_for, render_template from werkzeug.utils import secure_filename # 取得目前檔案所在的資料夾 SRC_PATH = pathlib.Path(__file__).parent.absolute() UPLOAD_FOLDER = os.path.join(SRC_PATH, 'static', 'uploads') app = Flask(__name__) app.secret_key = b'_5#y2L"F4Q8z\n\xec]/' # 請自行修改密鑰 app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['MAX_CONTENT_LENGTH'] = 3 * 1024 * 1024 ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} @app.route('/') def index(): return render_template('index.html') @app.route('/', methods=['POST']) def upload_file(): res = handle_file(request) if res['msg'] == 'ok': flash('影像上傳完畢!') return render_template('index.html', filename=res['filename']) elif res['msg'] == 'type_error': flash('僅允許上傳png, jpg, jpeg和gif影像檔') elif res['msg'] == 'empty': flash('請選擇要上傳的影像') elif res['msg'] == 'no_file': flash('沒有上傳檔案') return redirect(url_for('index')) # 令瀏覽器跳回首頁 @app.route('/esp32cam', methods=['POST']) def esp32cam(): res = handle_file(request) return res['msg'] def handle_file(request): if 'filename' not in request.files: return {"msg": 'no_file'} # 傳回代表「沒有檔案」的訊息 file = request.files['filename'] # 取得上傳檔 if file.filename == '': return {"msg": 'empty'} # 傳回代表「空白」的訊息 if file: file_type = filetype.guess_extension(file) # 判斷上傳檔的類型 if file_type in ALLOWED_EXTENSIONS: file.stream.seek(0) # filename = secure_filename(file.filename) # 重新設定檔名:日期時間 + ‘.’ + ‘副檔名’ filename = str(datetime.datetime.now()).replace( ':', '_') + '.' + file_type file.save(os.path.join( app.config['UPLOAD_FOLDER'], filename)) # 傳回代表上傳成功的訊息以及檔名。 return {"msg": 'ok', "filename": filename} else: return {"msg": 'type_error'} # 傳回代表「檔案類型錯誤」的訊息 @app.route('/img/<filename>') def display_image(filename): return redirect(url_for('static', filename='uploads/' + filename)) if __name__ == "__main__": app.run(host='0.0.0.0', port=80)
您好,想請教我應該如何讓ESP32-CAM拍照後將照片上傳至FLASK,並請FLASK上傳雲端辨識訓練模型,並回傳訊息至資料庫(先不管資料庫這一段),我目前遇到無法讓ESP32去連結flask,參考您的程式,__file__,這個我也無法定義,應該怎麼做比較好?
這是一個HTTP前端(ESP32)+ 後端(Flask)的應用,建議分開除錯,例如,編寫一個透過HTML表單上傳影像的Flask伺服器程式,確認OK,再測試ESP32的上傳影像程式是否正常。
遇到ESP32連結在GCP上的FLASK,ESP32一直產生502得回覆,請問該怎麼解決?