|
|
@ -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"}
|
|
||||||
]
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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"}
|
||||||
|
]
|
||||||
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
|
@ -5,8 +5,7 @@ from kivy.config import Config
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Kivy 앱의 크기와 설정을 고정합니다.
|
# Kivy 앱 설정
|
||||||
# 풀스크린과 테두리 없음을 설정하여 라즈베리파이 LCD에 맞춰 실행되도록 합니다.
|
|
||||||
Config.set('graphics', 'fullscreen', '1')
|
Config.set('graphics', 'fullscreen', '1')
|
||||||
Config.set('graphics', 'borderless', '1')
|
Config.set('graphics', 'borderless', '1')
|
||||||
Config.set('graphics', 'resizable', '0')
|
Config.set('graphics', 'resizable', '0')
|
||||||
|
|
@ -14,39 +13,45 @@ Config.set('graphics', 'width', '480')
|
||||||
Config.set('graphics', 'height', '320')
|
Config.set('graphics', 'height', '320')
|
||||||
Config.set('graphics', 'show_cursor', '0')
|
Config.set('graphics', 'show_cursor', '0')
|
||||||
|
|
||||||
# 서버의 블루투스 MAC 주소와 UUID를 설정합니다.
|
|
||||||
# 이 값은 갤럭시북의 정보와 일치해야 합니다.
|
|
||||||
SERVER_MAC = '8C:E9:EE:C9:33:4D'
|
SERVER_MAC = '8C:E9:EE:C9:33:4D'
|
||||||
PORT = 5
|
PORT = 5
|
||||||
|
|
||||||
|
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
from kivy.uix.gridlayout import GridLayout
|
from kivy.uix.gridlayout import GridLayout
|
||||||
from kivy.uix.label import Label
|
from kivy.uix.label import Label
|
||||||
from kivy.uix.image import Image
|
from kivy.uix.image import Image
|
||||||
from kivy.uix.behaviors import ButtonBehavior
|
from kivy.uix.behaviors import ButtonBehavior
|
||||||
|
from kivy.uix.button import Button
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.graphics import Color, RoundedRectangle
|
from kivy.graphics import Color, RoundedRectangle, Line
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
|
||||||
|
|
||||||
# Kivy 애플리케이션 클래스
|
|
||||||
class DashboardApp(App):
|
class DashboardApp(App):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.theme_mode = 'dark' # 기본 테마
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.client_sock = None
|
self.client_sock = None
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
self.status_label = Label(text="Connecting...", font_size=20, color=(1, 1, 0, 1))
|
self.status_label = Label(text="Connecting...", font_size=20, color=(1, 1, 0, 1))
|
||||||
|
|
||||||
# Kivy UI 구성
|
|
||||||
root = BoxLayout(orientation='vertical', padding=10)
|
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)
|
title_bar = BoxLayout(orientation='horizontal', size_hint_y=None, height=40)
|
||||||
|
|
||||||
grid = GridLayout(cols=4, rows=2, spacing=10, padding=1)
|
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)
|
||||||
|
|
||||||
# cmder.json 파일에서 버튼 데이터 로드
|
|
||||||
try:
|
try:
|
||||||
with open("cmders.json", "r", encoding="utf-8") as f:
|
with open("cmders.json", "r", encoding="utf-8") as f:
|
||||||
self.cmders = json.load(f)
|
self.cmders = json.load(f)
|
||||||
|
|
@ -67,14 +72,29 @@ class DashboardApp(App):
|
||||||
self.status_label.height = 30
|
self.status_label.height = 30
|
||||||
root.add_widget(self.status_label)
|
root.add_widget(self.status_label)
|
||||||
|
|
||||||
# 연결 시도 시작
|
|
||||||
print("[DEBUG] 초기 연결 시도 시작...")
|
print("[DEBUG] 초기 연결 시도 시작...")
|
||||||
self.connect_scheduled_event = Clock.schedule_once(self.connect_to_server, 1)
|
self.connect_scheduled_event = Clock.schedule_once(self.connect_to_server, 1)
|
||||||
|
|
||||||
|
self.apply_theme() # 초기 테마 적용
|
||||||
return root
|
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):
|
def connect_to_server(self, dt=0):
|
||||||
"""서버에 연결을 시도하는 함수입니다."""
|
|
||||||
if self.client_sock:
|
if self.client_sock:
|
||||||
self.client_sock.close()
|
self.client_sock.close()
|
||||||
self.client_sock = None
|
self.client_sock = None
|
||||||
|
|
@ -85,13 +105,10 @@ class DashboardApp(App):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.client_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
|
self.client_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
|
||||||
# self.client_sock.settimeout(5.0)
|
|
||||||
self.client_sock.connect((SERVER_MAC, PORT))
|
self.client_sock.connect((SERVER_MAC, PORT))
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
self.update_status_label("Connected!")
|
self.update_status_label("Connected!")
|
||||||
print("[DEBUG] 연결 성공!")
|
print("[DEBUG] 연결 성공!")
|
||||||
|
|
||||||
# 연결 성공 시 5초마다 상태 업데이트 스케줄링
|
|
||||||
Clock.schedule_interval(self.get_system_status, 5)
|
Clock.schedule_interval(self.get_system_status, 5)
|
||||||
|
|
||||||
except bluetooth.btcommon.BluetoothError as e:
|
except bluetooth.btcommon.BluetoothError as e:
|
||||||
|
|
@ -100,12 +117,9 @@ class DashboardApp(App):
|
||||||
if self.client_sock:
|
if self.client_sock:
|
||||||
self.client_sock.close()
|
self.client_sock.close()
|
||||||
self.client_sock = None
|
self.client_sock = None
|
||||||
# 연결 실패 시 5초 후 재시도
|
|
||||||
Clock.schedule_once(self.connect_to_server, 5)
|
Clock.schedule_once(self.connect_to_server, 5)
|
||||||
|
|
||||||
|
|
||||||
def get_system_status(self, dt):
|
def get_system_status(self, dt):
|
||||||
"""서버에 시스템 상태를 요청하고 응답을 받습니다."""
|
|
||||||
if not self.is_connected or not self.client_sock:
|
if not self.is_connected or not self.client_sock:
|
||||||
print("[DEBUG] 연결이 끊어져 상태 업데이트 중단.")
|
print("[DEBUG] 연결이 끊어져 상태 업데이트 중단.")
|
||||||
Clock.unschedule(self.get_system_status)
|
Clock.unschedule(self.get_system_status)
|
||||||
|
|
@ -128,12 +142,11 @@ class DashboardApp(App):
|
||||||
def update_status_label(self, text):
|
def update_status_label(self, text):
|
||||||
self.status_label.text = text
|
self.status_label.text = text
|
||||||
if "Connected" in text or "CPU" in 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:
|
else:
|
||||||
self.status_label.color = (1, 0, 0, 1) # 빨간색
|
self.status_label.color = (1, 0, 0, 1)
|
||||||
|
|
||||||
def send_command(self, command):
|
def send_command(self, command):
|
||||||
"""UI에서 호출될 함수: 서버로 명령을 보냅니다."""
|
|
||||||
if not self.is_connected or not self.client_sock:
|
if not self.is_connected or not self.client_sock:
|
||||||
self.update_status_label("Not connected. Cannot send command.")
|
self.update_status_label("Not connected. Cannot send command.")
|
||||||
print("Not connected to server.")
|
print("Not connected to server.")
|
||||||
|
|
@ -154,8 +167,6 @@ class DashboardApp(App):
|
||||||
Clock.unschedule(self.get_system_status)
|
Clock.unschedule(self.get_system_status)
|
||||||
self.connect_to_server()
|
self.connect_to_server()
|
||||||
|
|
||||||
|
|
||||||
# 버튼 위젯 클래스 (이전과 동일)
|
|
||||||
class IconButton(ButtonBehavior, BoxLayout):
|
class IconButton(ButtonBehavior, BoxLayout):
|
||||||
def __init__(self, icon_path, cmd, app_instance, **kwargs):
|
def __init__(self, icon_path, cmd, app_instance, **kwargs):
|
||||||
super().__init__(orientation='vertical', **kwargs)
|
super().__init__(orientation='vertical', **kwargs)
|
||||||
|
|
@ -163,15 +174,20 @@ class IconButton(ButtonBehavior, BoxLayout):
|
||||||
self.app_instance = app_instance
|
self.app_instance = app_instance
|
||||||
|
|
||||||
with self.canvas.before:
|
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.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))
|
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.pos = self.pos
|
||||||
self.rect.size = self.size
|
self.rect.size = self.size
|
||||||
|
self.border.rectangle = (self.x, self.y, self.width, self.height)
|
||||||
|
|
||||||
def on_press(self):
|
def on_press(self):
|
||||||
print(f"[DEBUG] 버튼 클릭됨: {self.cmd}")
|
print(f"[DEBUG] 버튼 클릭됨: {self.cmd}")
|
||||||
|
|
@ -179,7 +195,3 @@ class IconButton(ButtonBehavior, BoxLayout):
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
DashboardApp().run()
|
DashboardApp().run()
|
||||||
# 버전 체크용 코드: 파일이 올바르게 복사되었는지 확인합니다.
|
|
||||||
# 이 숫자는 이 코드가 생성된 시점을 나타내는 고유 식별자입니다.
|
|
||||||
print(f"File version: 8207010")
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||