186 lines
7.0 KiB
Python
186 lines
7.0 KiB
Python
import json
|
|
import bluetooth
|
|
import threading
|
|
from kivy.config import Config
|
|
import time
|
|
import sys
|
|
|
|
# Kivy 앱의 크기와 설정을 고정합니다.
|
|
# 풀스크린과 테두리 없음을 설정하여 라즈베리파이 LCD에 맞춰 실행되도록 합니다.
|
|
Config.set('graphics', 'fullscreen', '1')
|
|
Config.set('graphics', 'borderless', '1')
|
|
Config.set('graphics', 'resizable', '0')
|
|
Config.set('graphics', 'width', '480')
|
|
Config.set('graphics', 'height', '320')
|
|
Config.set('graphics', 'show_cursor', '0')
|
|
|
|
# 서버의 블루투스 MAC 주소와 UUID를 설정합니다.
|
|
# 이 값은 갤럭시북의 정보와 일치해야 합니다.
|
|
SERVER_MAC = '8C:E9:EE:C9:33:4D'
|
|
PORT = 5
|
|
|
|
|
|
from kivy.app import App
|
|
from kivy.uix.boxlayout import BoxLayout
|
|
from kivy.uix.gridlayout import GridLayout
|
|
from kivy.uix.label import Label
|
|
from kivy.uix.image import Image
|
|
from kivy.uix.behaviors import ButtonBehavior
|
|
from kivy.core.window import Window
|
|
from kivy.graphics import Color, RoundedRectangle
|
|
from kivy.clock import Clock
|
|
|
|
|
|
# Kivy 애플리케이션 클래스
|
|
class DashboardApp(App):
|
|
def build(self):
|
|
self.client_sock = None
|
|
self.is_connected = False
|
|
self.status_label = Label(text="Connecting...", font_size=20, color=(1, 1, 0, 1))
|
|
|
|
# Kivy UI 구성
|
|
root = BoxLayout(orientation='vertical', padding=10)
|
|
|
|
title = Label(text="MK's GalaxyBook5 Dashboard", font_size=25, size_hint_y=None, height=40)
|
|
root.add_widget(title)
|
|
|
|
grid = GridLayout(cols=4, rows=2, spacing=10, padding=1)
|
|
|
|
# cmder.json 파일에서 버튼 데이터 로드
|
|
try:
|
|
with open("cmders.json", "r", encoding="utf-8") as f:
|
|
self.cmders = json.load(f)
|
|
except FileNotFoundError:
|
|
self.cmders = []
|
|
print("cmders.json 파일을 찾을 수 없습니다. 기본값으로 실행합니다.")
|
|
|
|
for item in self.cmders:
|
|
icon_path = item["icons_path"] if item["icons_path"] else "icons/default.png"
|
|
cmd = item["cmd"]
|
|
btn = IconButton(icon_path=icon_path, cmd=cmd, app_instance=self)
|
|
grid.add_widget(btn)
|
|
|
|
root.add_widget(grid)
|
|
|
|
self.status_label.text = "Attempting to connect..."
|
|
self.status_label.size_hint_y = None
|
|
self.status_label.height = 30
|
|
root.add_widget(self.status_label)
|
|
|
|
# 연결 시도 시작
|
|
print("[DEBUG] 초기 연결 시도 시작...")
|
|
self.connect_scheduled_event = Clock.schedule_once(self.connect_to_server, 1)
|
|
|
|
return root
|
|
|
|
def connect_to_server(self, dt=0):
|
|
"""서버에 연결을 시도하는 함수입니다."""
|
|
if self.client_sock:
|
|
self.client_sock.close()
|
|
self.client_sock = None
|
|
|
|
self.is_connected = False
|
|
self.update_status_label("Connecting...")
|
|
print(f"[DEBUG] 연결 시도: MAC={SERVER_MAC}, PORT={PORT}")
|
|
|
|
try:
|
|
self.client_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
|
|
# self.client_sock.settimeout(5.0)
|
|
self.client_sock.connect((SERVER_MAC, PORT))
|
|
self.is_connected = True
|
|
self.update_status_label("Connected!")
|
|
print("[DEBUG] 연결 성공!")
|
|
|
|
# 연결 성공 시 5초마다 상태 업데이트 스케줄링
|
|
Clock.schedule_interval(self.get_system_status, 5)
|
|
|
|
except bluetooth.btcommon.BluetoothError as e:
|
|
self.update_status_label(f"Connection Failed: {e}")
|
|
print(f"[DEBUG] 연결 실패: {e}. 5초 후 재시도...")
|
|
if self.client_sock:
|
|
self.client_sock.close()
|
|
self.client_sock = None
|
|
# 연결 실패 시 5초 후 재시도
|
|
Clock.schedule_once(self.connect_to_server, 5)
|
|
|
|
|
|
def get_system_status(self, dt):
|
|
"""서버에 시스템 상태를 요청하고 응답을 받습니다."""
|
|
if not self.is_connected or not self.client_sock:
|
|
print("[DEBUG] 연결이 끊어져 상태 업데이트 중단.")
|
|
Clock.unschedule(self.get_system_status)
|
|
self.connect_to_server()
|
|
return
|
|
|
|
try:
|
|
self.client_sock.send("get_status".encode('utf-8'))
|
|
data = self.client_sock.recv(1024)
|
|
status_text = data.decode('utf-8')
|
|
self.update_status_label(status_text)
|
|
|
|
except bluetooth.btcommon.BluetoothError as e:
|
|
self.is_connected = False
|
|
self.update_status_label(f"Connection Lost: {e}")
|
|
print(f"[DEBUG] 통신 오류: {e}. 재연결 시도...")
|
|
Clock.unschedule(self.get_system_status)
|
|
self.connect_to_server()
|
|
|
|
def update_status_label(self, text):
|
|
self.status_label.text = text
|
|
if "Connected" in text or "CPU" in text:
|
|
self.status_label.color = (0, 1, 0, 1) # 녹색
|
|
else:
|
|
self.status_label.color = (1, 0, 0, 1) # 빨간색
|
|
|
|
def send_command(self, command):
|
|
"""UI에서 호출될 함수: 서버로 명령을 보냅니다."""
|
|
if not self.is_connected or not self.client_sock:
|
|
self.update_status_label("Not connected. Cannot send command.")
|
|
print("Not connected to server.")
|
|
return
|
|
|
|
try:
|
|
print(f"[DEBUG] '{command}' 명령 전송 시도...")
|
|
self.client_sock.send(command.encode('utf-8'))
|
|
data = self.client_sock.recv(1024)
|
|
response_text = data.decode('utf-8')
|
|
self.update_status_label(f"Response: {response_text}")
|
|
print(f"[DEBUG] 서버 응답: {response_text}")
|
|
|
|
except bluetooth.btcommon.BluetoothError as e:
|
|
self.is_connected = False
|
|
self.update_status_label(f"Send failed: {e}")
|
|
print(f"[DEBUG] 전송 오류: {e}. 연결 끊김...")
|
|
Clock.unschedule(self.get_system_status)
|
|
self.connect_to_server()
|
|
|
|
|
|
# 버튼 위젯 클래스 (이전과 동일)
|
|
class IconButton(ButtonBehavior, BoxLayout):
|
|
def __init__(self, icon_path, cmd, app_instance, **kwargs):
|
|
super().__init__(orientation='vertical', **kwargs)
|
|
self.cmd = cmd
|
|
self.app_instance = app_instance
|
|
|
|
with self.canvas.before:
|
|
Color(0.2, 0.2, 0.2, 1)
|
|
self.rect = RoundedRectangle(radius=[20], pos=self.pos, size=self.size)
|
|
|
|
self.bind(pos=self.update_rect, size=self.update_rect)
|
|
self.add_widget(Image(source=icon_path, size_hint=(1, 1), allow_stretch=True, keep_ratio=False))
|
|
|
|
def update_rect(self, *args):
|
|
self.rect.pos = self.pos
|
|
self.rect.size = self.size
|
|
|
|
def on_press(self):
|
|
print(f"[DEBUG] 버튼 클릭됨: {self.cmd}")
|
|
self.app_instance.send_command(self.cmd)
|
|
|
|
if __name__ == "__main__":
|
|
DashboardApp().run()
|
|
# 버전 체크용 코드: 파일이 올바르게 복사되었는지 확인합니다.
|
|
# 이 숫자는 이 코드가 생성된 시점을 나타내는 고유 식별자입니다.
|
|
print(f"File version: 8207010")
|
|
|