rpi kivy dashboard
This commit is contained in:
mkparkrpi 2025-08-30 07:45:54 +09:00
parent 2f84848aca
commit 56dc52b1f1
6 changed files with 426 additions and 0 deletions

10
rpiKivyDash/cmders.json Normal file
View File

@ -0,0 +1,10 @@
[
{"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"}
]

185
rpiKivyDash/main.py Normal file
View File

@ -0,0 +1,185 @@
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")

View File

@ -0,0 +1,11 @@
certifi==2025.8.3
charset-normalizer==3.4.3
docutils==0.22
filetype==1.2.0
idna==3.10
Kivy==2.3.1
Kivy-Garden==0.1.5
PyBluez @ git+https://github.com/pybluez/pybluez.git@82cbba8a1ebd4c1e3442dfafd8581d58c50fa39e
Pygments==2.19.2
requests==2.32.5
urllib3==2.5.0

View File

@ -0,0 +1,185 @@
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")

View File

@ -0,0 +1,15 @@
from kivy.config import Config
Config.set('graphics', 'fullscreen', 'auto') # 또는 '1'
Config.set('graphics', 'borderless', '1')
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'width', '480') # 라즈베리파이 해상도에 맞게 조정
Config.set('graphics', 'height', '320') # 예: 800x480 LCD
from kivy.app import App
from kivy.uix.button import Button
class MyApp(App):
def build(self):
return Button(text='LAUNCH', font_size='40sp')
MyApp().run()

View File

@ -0,0 +1,20 @@
import bluetooth
import time
server_mac = '8C:E9:EE:C9:33:4D'
port = 5
while True:
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((server_mac, port))
try:
# sock.send("get_status".encode())
sock.send("get_status".encode('utf-8'))
data = sock.recv(1024)
print("서버 응답:", data.decode())
except bluetooth.btcommon.BluetoothError as e:
print("Bluetooth 오류 발생:", e)
finally:
sock.close()
time.sleep(2)