pyqt6Dashboard/rpiKivyStreamDeck/main.py

199 lines
7.3 KiB
Python

import json
import bluetooth
import threading
from kivy.config import Config
import time
import sys
# Kivy 앱 설정
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')
# SERVER_MAC = '8C:E9:EE:C9:33:4D'
SERVER_MAC = '00:72:EE:DE:15:79'
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.uix.button import Button
from kivy.core.window import Window
from kivy.graphics import Color, RoundedRectangle, Line
from kivy.clock import Clock
class DashboardApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.theme_mode = 'dark' # 기본 테마
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))
root = BoxLayout(orientation='vertical', padding=10)
# 타이틀 바 + 테마 버튼
title_bar = BoxLayout(orientation='horizontal', size_hint_y=None, height=40)
self.title_label = Label(text="MK's GalaxyBook5 Stream Deck", font_size=25, halign='left', valign='middle')
theme_btn = Button(text='dark', size_hint_x=None, width=60)
theme_btn.bind(on_press=self.toggle_theme)
title_bar.add_widget(self.title_label)
title_bar.add_widget(theme_btn)
root.add_widget(title_bar)
grid = GridLayout(cols=4, rows=2, spacing=10, padding=5)
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)
self.apply_theme() # 초기 테마 적용
return root
def toggle_theme(self, instance):
self.theme_mode = 'dark' if self.theme_mode == 'light' else 'light'
instance.text = 'Light' if self.theme_mode == 'light' else 'Dark'
print(f"[DEBUG] 테마 변경됨: {self.theme_mode}")
self.apply_theme()
def apply_theme(self):
if self.theme_mode == 'dark':
Window.clearcolor = (0.1, 0.1, 0.1, 1)
self.status_label.color = (0.8, 0.8, 0.2, 1)
self.title_label.color = (1, 1, 1, 1) # 밝은 글씨
else:
Window.clearcolor = (1, 1, 1, 1)
self.status_label.color = (0.2, 0.2, 0.2, 1)
self.title_label.color = (0, 0, 0, 1) # 어두운 글씨
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.connect((SERVER_MAC, PORT))
self.is_connected = True
self.update_status_label("Connected!")
print("[DEBUG] 연결 성공!")
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
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):
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.5, 0.5, 0.5, 1)
self.rect = RoundedRectangle(radius=[20], pos=self.pos, size=self.size)
with self.canvas.after:
Color(0.6, 0.6, 0.6, 1)
self.border = Line(rectangle=(self.x, self.y, self.width, self.height), width=1)
self.bind(pos=self.update_graphics, size=self.update_graphics)
self.add_widget(Image(source=icon_path, size_hint=(1, 1), allow_stretch=True, keep_ratio=False))
def update_graphics(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
self.border.rectangle = (self.x, self.y, self.width, self.height)
def on_press(self):
print(f"[DEBUG] 버튼 클릭됨: {self.cmd}")
self.app_instance.send_command(self.cmd)
if __name__ == "__main__":
DashboardApp().run()