2026-08-07 15:07:40 +09:00
|
|
|
"""팔레타이징 앱 진입점.
|
|
|
|
|
|
|
|
|
|
Flask(백엔드) + pywebview(데스크톱 창) + waitress(WSGI 서버) 구성.
|
|
|
|
|
로봇 제어 로직과 HTTP API 는 전부 api_routes.py 에 있다.
|
|
|
|
|
PyInstaller 로 빌드 시(frozen) 템플릿 경로가 임시 폴더(_MEIPASS)로 바뀌는 것을 처리한다.
|
|
|
|
|
"""
|
2026-08-04 14:30:00 +09:00
|
|
|
from flask import Flask, render_template, request, jsonify
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
2026-08-07 15:07:40 +09:00
|
|
|
from api_routes import api_routes
|
2026-08-04 14:30:00 +09:00
|
|
|
import webview
|
|
|
|
|
from waitress import serve
|
|
|
|
|
|
2026-08-07 15:07:40 +09:00
|
|
|
# PyInstaller 실행파일(frozen)이면 압축 해제된 임시 폴더에서 템플릿을 찾는다
|
2026-08-04 14:30:00 +09:00
|
|
|
if getattr(sys, 'frozen', False):
|
|
|
|
|
template_folder = os.path.join(sys._MEIPASS, 'templates')
|
|
|
|
|
app = Flask(__name__, template_folder=template_folder, static_url_path='/static')
|
|
|
|
|
else:
|
|
|
|
|
app = Flask(__name__, static_url_path='/static')
|
|
|
|
|
|
2026-08-07 15:07:40 +09:00
|
|
|
app.register_blueprint(api_routes) # 로봇 제어 API 라우트 등록
|
2026-08-04 14:30:00 +09:00
|
|
|
|
|
|
|
|
|
2026-08-07 15:07:40 +09:00
|
|
|
# ── 화면 라우트 ──────────────────────────────────────────────
|
2026-08-04 14:30:00 +09:00
|
|
|
@app.route('/')
|
|
|
|
|
def index():
|
2026-08-07 15:07:40 +09:00
|
|
|
"""메인 화면: 팔레트 선택/적재 배치 설정."""
|
2026-08-04 14:30:00 +09:00
|
|
|
return render_template('layer.html')
|
|
|
|
|
|
|
|
|
|
@app.route('/progress')
|
|
|
|
|
def progess():
|
2026-08-07 15:07:40 +09:00
|
|
|
"""일반 적재 진행 현황 화면."""
|
2026-08-04 14:30:00 +09:00
|
|
|
return render_template('progress.html')
|
2026-08-07 15:07:40 +09:00
|
|
|
|
2026-08-04 14:30:00 +09:00
|
|
|
@app.route('/oneLineProgress')
|
|
|
|
|
def oneLineProgess():
|
2026-08-07 15:07:40 +09:00
|
|
|
"""한줄쌓기 진행 현황 화면."""
|
2026-08-04 14:30:00 +09:00
|
|
|
return render_template('oneLineProgress.html')
|
|
|
|
|
|
2026-08-07 15:07:40 +09:00
|
|
|
|
|
|
|
|
# ── 종료 처리 ────────────────────────────────────────────────
|
2026-08-04 14:30:00 +09:00
|
|
|
def shutdown_waitress_server():
|
2026-08-07 15:07:40 +09:00
|
|
|
"""waitress 서버 및 프로세스 전체 종료."""
|
2026-08-04 14:30:00 +09:00
|
|
|
print("Shutting down the server...")
|
|
|
|
|
os._exit(0)
|
|
|
|
|
|
|
|
|
|
def destroy(window):
|
2026-08-07 15:07:40 +09:00
|
|
|
"""pywebview 창 닫기."""
|
2026-08-04 14:30:00 +09:00
|
|
|
print('Destroying window..')
|
|
|
|
|
window.destroy()
|
|
|
|
|
print('Destroyed!')
|
|
|
|
|
|
|
|
|
|
@app.route('/shutdown', methods=['POST'])
|
|
|
|
|
def shutdown():
|
2026-08-07 15:07:40 +09:00
|
|
|
"""UI 종료 버튼: 창 닫고 서버/프로세스 종료."""
|
2026-08-04 14:30:00 +09:00
|
|
|
destroy(test)
|
|
|
|
|
shutdown_waitress_server()
|
|
|
|
|
return 'Server shutting down'
|
|
|
|
|
|
|
|
|
|
|
2026-08-07 15:07:40 +09:00
|
|
|
port = 5000
|
2026-08-04 14:30:00 +09:00
|
|
|
|
2026-08-07 15:07:40 +09:00
|
|
|
# pywebview 가 Flask 앱을 감싸는 데스크톱 창 생성
|
2026-08-04 14:30:00 +09:00
|
|
|
test = webview.create_window('Palletizing', app)
|
2026-08-07 15:07:40 +09:00
|
|
|
|
2026-08-04 14:30:00 +09:00
|
|
|
if __name__ == "__main__":
|
2026-08-07 15:07:40 +09:00
|
|
|
# webview.start()가 창이 닫힐 때까지 블록되고,
|
|
|
|
|
# 창이 닫힌 뒤에는 waitress 단독 서버로 계속 서비스한다(0.0.0.0:5000).
|
2026-08-04 14:30:00 +09:00
|
|
|
webview.start()
|
|
|
|
|
serve(app, host="0.0.0.0", port=port)
|