rpiKivyDash -> rpiKivyStreamDeck
This commit is contained in:
mkparkrpi 2025-08-30 12:40:12 +09:00
parent 56dc52b1f1
commit 4bfddc2be8
19 changed files with 91 additions and 53 deletions

View File

@ -1,10 +0,0 @@
[
{"id": 1, "icons_path": "icons/calc.png", "cmd": "calc"},
{"id": 2, "icons_path": "icons/notepad.png", "cmd": "notepad"},
{"id": 3, "icons_path": "icons/gemini.png", "cmd": "gemini"},
{"id": 4, "icons_path": "", "cmd": "copilot"},
{"id": 5, "icons_path": "", "cmd": "calc"},
{"id": 6, "icons_path": "", "cmd": "calc"},
{"id": 7, "icons_path": "", "cmd": "calc"},
{"id": 8, "icons_path": "", "cmd": "calc"}
]

Binary file not shown.

View File

@ -0,0 +1,12 @@
#!/bin/bash
export DISPLAY=:0
export XAUTHORITY=/home/mkpark/.Xauthority
# 화면 연결 상태 확인
if xrandr | grep " connected" | grep -v "disconnected"; then
echo "Display is connected. Restarting service..."
systemctl restart kivy-dashboard.service
else
echo "Display not ready yet."
fi

View File

@ -0,0 +1,10 @@
[
{"id": 1, "icons_path": "icons/youtube.png", "cmd": "youtube"},
{"id": 2, "icons_path": "icons/copilot.png", "cmd": "copilot"},
{"id": 3, "icons_path": "icons/gemini.png", "cmd": "gemini"},
{"id": 4, "icons_path": "icons/chatgpt.png", "cmd": "chatgpt"},
{"id": 5, "icons_path": "icons/gitea.png", "cmd": "gitea"},
{"id": 6, "icons_path": "icons/redmine.png", "cmd": "redmine"},
{"id": 7, "icons_path": "icons/github.png", "cmd": "github"},
{"id": 8, "icons_path": "icons/taskmgr.png", "cmd": "taskmgr"}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -5,8 +5,7 @@ from kivy.config import Config
import time
import sys
# Kivy 앱의 크기와 설정을 고정합니다.
# 풀스크린과 테두리 없음을 설정하여 라즈베리파이 LCD에 맞춰 실행되도록 합니다.
# Kivy 앱 설정
Config.set('graphics', 'fullscreen', '1')
Config.set('graphics', 'borderless', '1')
Config.set('graphics', 'resizable', '0')
@ -14,46 +13,52 @@ 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.uix.button import Button
from kivy.core.window import Window
from kivy.graphics import Color, RoundedRectangle
from kivy.graphics import Color, RoundedRectangle, Line
from kivy.clock import Clock
# Kivy 애플리케이션 클래스
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))
# 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 파일에서 버튼 데이터 로드
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"]
@ -64,34 +69,46 @@ class DashboardApp(App):
self.status_label.text = "Attempting to connect..."
self.status_label.size_hint_y = None
self.status_label.height = 30
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.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:
@ -100,24 +117,21 @@ class DashboardApp(App):
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}")
@ -128,12 +142,11 @@ class DashboardApp(App):
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) # 녹색
self.status_label.color = (0, 1, 0, 1)
else:
self.status_label.color = (1, 0, 0, 1) # 빨간색
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.")
@ -146,7 +159,7 @@ class DashboardApp(App):
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}")
@ -154,8 +167,6 @@ class DashboardApp(App):
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)
@ -163,15 +174,20 @@ class IconButton(ButtonBehavior, BoxLayout):
self.app_instance = app_instance
with self.canvas.before:
Color(0.2, 0.2, 0.2, 1)
Color(0.5, 0.5, 0.5, 1)
self.rect = RoundedRectangle(radius=[20], pos=self.pos, size=self.size)
self.bind(pos=self.update_rect, size=self.update_rect)
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_rect(self, *args):
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}")
@ -179,7 +195,3 @@ class IconButton(ButtonBehavior, BoxLayout):
if __name__ == "__main__":
DashboardApp().run()
# 버전 체크용 코드: 파일이 올바르게 복사되었는지 확인합니다.
# 이 숫자는 이 코드가 생성된 시점을 나타내는 고유 식별자입니다.
print(f"File version: 8207010")

View File

@ -0,0 +1,14 @@
[Unit]
Description=Kivy Dashboard Service
After=network.target
[Service]
ExecStart=/home/mkpark/pyqt6Dashboard/.venv/bin/python /home/mkpark/pyqt6Dashboard/rpiKivyStreamDeck/main.py
WorkingDirectory=/home/mkpark/pyqt6Dashboard/rpiKivyStreamDeck
Restart=always
User=mkpark
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/mkpark/.Xauthority
[Install]
WantedBy=graphical.target