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")