1
1
import logging
2
2
import time
3
3
import PySimpleGUI as sg
4
+
4
5
from controller import SteamDeckController
5
- from network import connect , Client
6
+ from video_stream import VideoStream
7
+ from network import connect , LockedClient
6
8
from typing import Any , Dict , List , Optional
7
9
from spec .ttypes import ARR_status , Mode , Giat
8
10
import queue
@@ -16,8 +18,11 @@ class SteamDeckUI:
16
18
def __init__ (self ):
17
19
self .connected = False
18
20
self .network_client : Client = None
19
- self ._connect_layout = self .get_connect_layout ()
20
- self ._op_layout = self .get_op_layout ()
21
+ self .network_socket = None
22
+ self .video_stream : VideoStream = None
23
+ self .logs_view = True
24
+ self ._connect_layout = None
25
+ self ._op_layout = None
21
26
22
27
self .ui_state : Dict [str , Any ] = {}
23
28
self .robot_state = ARR_status (
@@ -33,13 +38,12 @@ def __init__(self):
33
38
self .event_routes = {
34
39
"_button_connect" : self ._button_connect ,
35
40
"_button_disconnect" : self ._button_disconnect ,
36
- "_button_ping" : self ._button_ping
41
+ "_button_ping" : self ._button_ping ,
42
+ "_button_view" : self ._button_view
37
43
}
38
44
39
- self ._multiline_log = None
40
45
self .controller : Optional [SteamDeckController ] = None
41
46
42
-
43
47
def init_connect_window (self ):
44
48
self ._connect_layout = self .get_connect_layout ()
45
49
self .window = sg .Window ("Connect" , self ._connect_layout , finalize = True , font = self .FONT )
@@ -52,16 +56,20 @@ def init_op_window(self):
52
56
def get_connect_layout (self ) -> List [List [Any ]]:
53
57
return [
54
58
[
59
+ sg .Text ("RC: " ),
55
60
sg .Input ('localhost' , key = "_input_ip_addr" , size = 32 ),
56
61
sg .Input ('9090' , key = "_input_port" , size = 5 ),
57
62
],
63
+ [
64
+ sg .Text ("VD: " ),
65
+ sg .Input ('http://192.168.0.6:9999/stream' , key = '_input_video_addr' , size = 38 )
66
+ ],
58
67
[
59
68
sg .Button ("Connect" , key = "_button_connect" ),
60
69
],
61
70
]
62
71
63
72
def get_op_layout (self ) -> List [List [Any ]]:
64
- self ._multiline_log = sg .Multiline ('' , size = (64 ,18 ), key = "_multiline_log" , autoscroll = True )
65
73
return [
66
74
[
67
75
sg .Text ('M: N/A' , key = "_text_mode" ),
@@ -72,14 +80,13 @@ def get_op_layout(self) -> List[List[Any]]:
72
80
sg .Text ('Battery: N/A' , key = "_text_battery" ),
73
81
],
74
82
[
75
- # TODO insert image here
76
- self . _multiline_log
83
+ sg . Image ( key = "_image_stream" , visible = ( not self . logs_view )),
84
+ sg . Multiline ( '' , size = ( 64 , 18 ), key = " _multiline_log" , autoscroll = True , visible = self . logs_view )
77
85
],
78
86
[
79
87
sg .Text ("Connection quality: TBD" ),
80
88
sg .Button ("Ping" , key = "_button_ping" ),
81
- sg .Button ("Video: OFF" ),
82
- sg .Button ("Logs: OFF" ),
89
+ sg .Button ("View: LOGS" , key = "_button_view" ),
83
90
sg .Button ("Disconnect" , key = "_button_disconnect" )
84
91
]
85
92
]
@@ -96,33 +103,63 @@ def _button_connect(self):
96
103
if not self .connected :
97
104
host = self .ui_state ["_input_ip_addr" ]
98
105
port = int (self .ui_state ["_input_port" ])
99
- self .network_client = connect (host , port )
106
+ video_addr = self .ui_state ["_input_video_addr" ]
107
+ self .network_socket , self .network_client = connect (host , port )
100
108
self .connected = True
101
109
logger .info ("Connected to %s:%s" , host , port )
102
110
self .window .close ()
103
111
self .init_op_window ()
104
112
self .controller = SteamDeckController (self .network_client )
113
+ self .video_stream = VideoStream (video_addr )
114
+ if not self .logs_view :
115
+ self .video_stream .enable ()
105
116
else :
106
117
logger .warning ("Already connected!" )
107
118
119
+
108
120
def _button_disconnect (self ):
109
121
if self .connected :
110
- # TODO do disconnect logic here! Close Socket/etc
122
+ self .controller .terminate ()
123
+ self .controller = None
124
+ self .network_socket .close ()
125
+ self .network_client = None
126
+ self .video_stream .disable ()
111
127
self .window .close ()
112
128
self .init_connect_window ()
113
129
self .connected = False
114
130
logger .info ("Disconnected" )
115
131
else :
116
132
logger .warning ("Already disconnected!" )
117
133
134
+
118
135
def _button_ping (self ):
119
136
if self .connected :
120
137
self .network_client .ping ()
121
138
139
+
140
+ def _button_view (self ):
141
+ txt_map = {
142
+ True : "LOGS" ,
143
+ False : "VIDEO"
144
+ }
145
+
146
+ self .logs_view = not self .logs_view
147
+ self .window ["_multiline_log" ].update (visible = self .logs_view )
148
+ self .window ['_image_stream' ].update (visible = not self .logs_view )
149
+ self .window ["_button_view" ].update ("View: " + txt_map [self .logs_view ])
150
+ if self .logs_view :
151
+ self .video_stream .disable ()
152
+ else :
153
+ self .video_stream .enable ()
154
+
122
155
def update_op_values (self ):
123
- while not self .controller .log_queue .empty ():
124
- record = self .controller .log_queue .get ()
125
- self .window ['_multiline_log' ].update (record + "\n " , append = True )
156
+ if self .logs_view :
157
+ while not self .controller .log_queue .empty ():
158
+ record = self .controller .log_queue .get ()
159
+ self .window ['_multiline_log' ].update (record + "\n " , append = True )
160
+ else :
161
+ self .window ['_image_stream' ].update (data = self .video_stream .get_frame ())
162
+
126
163
self .robot_state = self .network_client .get_status ()
127
164
self .window ["_text_mode" ].update ("M: " + Mode ._VALUES_TO_NAMES [self .robot_state .mode ])
128
165
if self .robot_state .mode == Mode .WALK :
@@ -142,14 +179,16 @@ def run(self):
142
179
if self .connected :
143
180
self .update_op_values ()
144
181
self .window .refresh ()
145
- time .sleep (0.05 )
182
+ time .sleep (0.01 )
146
183
147
184
148
185
def refresh (self ):
149
186
self .window .refresh ()
150
187
188
+
151
189
def read (self ):
152
190
return window .read ()
153
191
192
+
154
193
def close (self ):
155
194
window .close ()
0 commit comments