10
10
from typing import Dict
11
11
import platform
12
12
import os
13
+ import numpy
13
14
14
15
if USE_OPENCV :
15
16
# import cv2
20
21
21
22
SCRIPT_DIR = os .path .dirname (os .path .realpath (__file__ ))
22
23
24
+ PLATFORM_ICON_PATH = None
23
25
if platform .system () == 'Windows' :
24
- sg . set_global_icon ( f'{ SCRIPT_DIR } /assets/icon.ico' )
26
+ PLATFORM_ICON_PATH = f'{ SCRIPT_DIR } /assets/icon.ico'
25
27
else :
26
- sg .set_global_icon (f'{ SCRIPT_DIR } /assets/icon.png' )
28
+ PLATFORM_ICON_PATH = f'{ SCRIPT_DIR } /assets/icon.png'
29
+
30
+ # Apply icon globally
31
+ sg .set_global_icon (PLATFORM_ICON_PATH )
27
32
28
33
CONF_TEXT_POE = ['ipTypeText' , 'ipText' , 'maskText' , 'gatewayText' , 'dnsText' , 'dnsAltText' , 'networkTimeoutText' , 'macText' ]
29
34
CONF_INPUT_POE = ['staticBut' , 'dynamicBut' , 'ip' , 'mask' , 'gateway' , 'dns' , 'dnsAlt' , 'networkTimeout' , 'mac' ]
@@ -38,27 +43,35 @@ def PrintException():
38
43
filename = f .f_code .co_filename
39
44
print ('Exception in {}, line {}; {}' .format (filename , lineno , exc_obj ))
40
45
41
- def check_ip (s : str , req = True ):
46
+ def Popup (msg , window ):
47
+ main_window_location = window .CurrentLocation ()
48
+ main_window_size = window .size
49
+ # Calculate the centered location for the new window
50
+ centered_location = (main_window_location [0 ] + (main_window_size [0 ] - 50 ) // 2 ,
51
+ main_window_location [1 ] + (main_window_size [1 ] - 50 ) // 2 )
52
+ return sg .Popup (msg , location = centered_location )
53
+
54
+ def check_ip (window , s : str , req = True ):
42
55
if s == "" :
43
56
return not req
44
57
spl = s .split ("." )
45
58
if len (spl ) != 4 :
46
- sg . Popup ("Wrong IP format.\n Value should be similar to 255.255.255.255" )
59
+ Popup ("Wrong IP format.\n Value should be similar to 255.255.255.255" , window = window )
47
60
return False
48
61
for num in spl :
49
62
if 255 < int (num ):
50
- sg . Popup ("Wrong IP format.\n Values can not be above 255!" )
63
+ Popup ("Wrong IP format.\n Values can not be above 255!" , window = window )
51
64
return False
52
65
return True
53
66
54
- def check_mac (s ):
67
+ def check_mac (window , s ):
55
68
if s .count (":" ) != 5 :
56
- sg . Popup ("Wrong MAC format.\n Value should be similar to FF:FF:FF:FF:FF:FF" )
69
+ Popup ("Wrong MAC format.\n Value should be similar to FF:FF:FF:FF:FF:FF" , window = window )
57
70
return False
58
71
for i in s .split (":" ):
59
72
for j in i :
60
73
if j > "F" or (j < "A" and not j .isdigit ()) or len (i ) != 2 :
61
- sg . Popup ("Wrong MAC format.\n Value should be similar to FF:FF:FF:FF:FF:FF" )
74
+ Popup ("Wrong MAC format.\n Value should be similar to FF:FF:FF:FF:FF:FF" , window = window )
62
75
return False
63
76
return True
64
77
@@ -113,7 +126,7 @@ def wait(self):
113
126
114
127
115
128
class SelectIP :
116
- def __init__ (self ):
129
+ def __init__ (self , window ):
117
130
self .ok = False
118
131
layout = [
119
132
[sg .Text ("Specify the custom IP of the OAK PoE\n camera you want to connect to" )],
@@ -124,15 +137,24 @@ def __init__(self):
124
137
[sg .Submit (), sg .Cancel ()],
125
138
]
126
139
self .window = sg .Window ("Specify IP" , layout , size = (300 ,110 ), modal = True , finalize = True )
140
+
141
+ main_window_location = window .CurrentLocation ()
142
+ main_window_size = window .size
143
+ new_window_size = self .window .size
144
+ # Calculate the centered location for the new window
145
+ centered_location = (main_window_location [0 ] + (main_window_size [0 ] - new_window_size [0 ]) // 2 ,
146
+ main_window_location [1 ] + (main_window_size [1 ] - new_window_size [1 ]) // 2 )
147
+ self .window .move (* centered_location )
148
+
127
149
def wait (self ):
128
150
event , values = self .window .Read ()
129
151
self .window .close ()
130
- if str (event ) == "Cancel" or values is None or not check_ip (values ["ip" ]):
152
+ if str (event ) == "Cancel" or values is None or not check_ip (self . window , values ["ip" ]):
131
153
return False , ""
132
154
return True , values ["ip" ]
133
155
134
156
class SearchDevice :
135
- def __init__ (self ):
157
+ def __init__ (self , window ):
136
158
self .infos = []
137
159
layout = [
138
160
[sg .Text ("Select an OAK camera you would like to connect to." , font = ('Arial' , 10 , 'bold' ))],
@@ -156,12 +178,22 @@ def __init__(self):
156
178
[sg .Button ('Search' , size = (15 , 2 ), font = ('Arial' , 10 , 'bold' ))],
157
179
]
158
180
self .window = sg .Window ("Select Device" , layout , size = (550 ,375 ), modal = True , finalize = True )
181
+
182
+ main_window_location = window .CurrentLocation ()
183
+ main_window_size = window .size
184
+ new_window_size = self .window .size
185
+ # Calculate the centered location for the new window
186
+ centered_location = (main_window_location [0 ] + (main_window_size [0 ] - new_window_size [0 ]) // 2 ,
187
+ main_window_location [1 ] + (main_window_size [1 ] - new_window_size [1 ]) // 2 )
188
+ self .window .move (* centered_location )
189
+
159
190
self .search_devices ()
160
191
161
192
def search_devices (self ):
162
193
self .infos = dai .XLinkConnection .getAllConnectedDevices ()
163
194
if not self .infos :
164
- sg .Popup ("No devices found." )
195
+ pass
196
+ # sg.Popup("No devices found.")
165
197
else :
166
198
rows = []
167
199
for info in self .infos :
@@ -257,43 +289,43 @@ def factoryReset(device: dai.DeviceInfo, type: dai.DeviceBootloader.Type):
257
289
258
290
def connectAndStartStreaming (dev ):
259
291
260
- # OpenCV
261
- if USE_OPENCV :
292
+ with dai .Device (dev ) as d :
262
293
# Create pipeline
263
294
pipeline = dai .Pipeline ()
295
+ # OpenCV
296
+ if USE_OPENCV :
297
+ camRgb = pipeline .create (dai .node .ColorCamera )
298
+ camRgb .setIspScale (1 ,3 )
299
+ videnc = pipeline .create (dai .node .VideoEncoder )
300
+ videnc .setDefaultProfilePreset (camRgb .getFps (), videnc .Properties .Profile .MJPEG )
301
+ xout = pipeline .create (dai .node .XLinkOut )
302
+ xout .setStreamName ("mjpeg" )
303
+ camRgb .video .link (videnc .input )
304
+ videnc .bitstream .link (xout .input )
264
305
265
- camRgb = pipeline .create (dai .node .ColorCamera )
266
- camRgb .setIspScale (1 ,3 )
267
- videnc = pipeline .create (dai .node .VideoEncoder )
268
- videnc .setDefaultProfilePreset (camRgb .getFps (), videnc .Properties .Profile .MJPEG )
269
- xout = pipeline .create (dai .node .XLinkOut )
270
- xout .setStreamName ("mjpeg" )
271
- camRgb .video .link (videnc .input )
272
- videnc .bitstream .link (xout .input )
273
-
274
- with dai .Device (pipeline , dev ) as d :
275
306
while not d .isClosed ():
276
307
mjpeg = d .getOutputQueue ('mjpeg' ).get ()
277
308
frame = cv2 .imdecode (mjpeg .getData (), cv2 .IMREAD_UNCHANGED )
278
309
cv2 .imshow ('Color Camera' , frame )
279
310
if cv2 .waitKey (1 ) == ord ('q' ):
280
311
cv2 .destroyWindow ('Color Camera' )
281
312
break
282
- else :
283
- # Create pipeline (no opencv)
284
- pipeline = dai .Pipeline ()
285
- camRgb = pipeline .create (dai .node .ColorCamera )
286
- camRgb .setIspScale (1 ,3 )
287
- camRgb .setPreviewSize (camRgb .getIspSize ())
288
- camRgb .setColorOrder (camRgb .Properties .ColorOrder .RGB )
289
-
290
- xout = pipeline .create (dai .node .XLinkOut )
291
- xout .input .setQueueSize (2 )
292
- xout .input .setBlocking (False )
293
- xout .setStreamName ("color" )
294
- camRgb .preview .link (xout .input )
295
-
296
- with dai .Device (pipeline , dev ) as d :
313
+ else :
314
+ camRgb = pipeline .create (dai .node .ColorCamera )
315
+ camRgb .setIspScale (1 ,3 )
316
+ firstSensor = d .getConnectedCameraFeatures ()[0 ]
317
+ camRgb .setPreviewSize (firstSensor .width // 3 , firstSensor .height // 3 )
318
+ camRgb .setColorOrder (camRgb .Properties .ColorOrder .RGB )
319
+
320
+ xout = pipeline .create (dai .node .XLinkOut )
321
+ xout .input .setQueueSize (2 )
322
+ xout .input .setBlocking (False )
323
+ xout .setStreamName ("color" )
324
+ camRgb .preview .link (xout .input )
325
+
326
+ # Start pipeline
327
+ d .startPipeline (pipeline )
328
+
297
329
frame = d .getOutputQueue ('color' , 2 , False ).get ()
298
330
width , height = frame .getWidth (), frame .getHeight ()
299
331
@@ -540,7 +572,7 @@ class DeviceManager:
540
572
541
573
def __init__ (self ) -> None :
542
574
self .window = sg .Window (title = "Device Manager" ,
543
- icon = "assets/icon.png" ,
575
+ icon = PLATFORM_ICON_PATH ,
544
576
layout = layout ,
545
577
size = (645 , 380 ),
546
578
finalize = True # So we can do First search for devices
@@ -556,7 +588,7 @@ def isPoE(self) -> bool:
556
588
return self .bl .getType () == dai .DeviceBootloader .Type .NETWORK
557
589
except Exception as ex :
558
590
PrintException ()
559
- sg . Popup (f'{ ex } ' )
591
+ Popup (f'{ ex } ' , self . window )
560
592
561
593
def isUsb (self ) -> bool :
562
594
return not self .isPoE ()
@@ -577,7 +609,7 @@ def run(self) -> None:
577
609
device = self .device
578
610
if deviceStateTxt (device .state ) == "BOOTED" :
579
611
# device is already booted somewhere else
580
- sg . Popup ("Device is already booted somewhere else!" )
612
+ Popup ("Device is already booted somewhere else!" , self . window )
581
613
else :
582
614
self .resetGui ()
583
615
self .bl = connectToDevice (device )
@@ -588,7 +620,7 @@ def run(self) -> None:
588
620
self .window .Element ('progress' ).update ("No device selected." )
589
621
elif event == "Search" :
590
622
self .getDevices () # Re-search devices for dropdown
591
- selDev = SearchDevice ()
623
+ selDev = SearchDevice (window = self . window )
592
624
di = selDev .wait ()
593
625
if di is not None :
594
626
self .resetGui ()
@@ -601,7 +633,7 @@ def run(self) -> None:
601
633
self .getConfigs ()
602
634
self .unlockConfig ()
603
635
elif event == "Specify IP" :
604
- select = SelectIP ()
636
+ select = SelectIP (window = self . window )
605
637
ok , ip = select .wait ()
606
638
if ok :
607
639
self .resetGui ()
@@ -655,14 +687,14 @@ def run(self) -> None:
655
687
print ("Factory reset cancelled." )
656
688
657
689
elif event == "Flash configuration" :
658
- self .flashConfig ()
659
- self .getConfigs ()
660
- self .resetGui ()
661
- if self .isUsb ():
662
- self .unlockConfig ()
663
- else :
664
- self .devices .clear ()
665
- self .window .Element ('devices' ).update ("Search for devices" , values = [])
690
+ if self .flashConfig () is not None :
691
+ self .getConfigs ()
692
+ self .resetGui ()
693
+ if self .isUsb ():
694
+ self .unlockConfig ()
695
+ else :
696
+ self .devices .clear ()
697
+ self .window .Element ('devices' ).update ("Search for devices" , values = [])
666
698
elif event == "Clear configuration" :
667
699
self .clearConfig ()
668
700
self .getConfigs ()
@@ -677,17 +709,17 @@ def run(self) -> None:
677
709
confJson = self .bl .readConfigData ()
678
710
sg .popup_scrolled (confJson , title = 'Configuration' )
679
711
except Exception as ex :
680
- sg . popup (f'No existing config to view ({ ex } )' )
712
+ Popup (f'No existing config to view ({ ex } )' , self . window )
681
713
682
714
elif event == "Flash application" :
683
715
file = sg .popup_get_file ("Select .dap file" , file_types = (('DepthAI Application Package' , '*.dap' ), ('All Files' , '*.* *' )))
684
716
flashFromFile (file , self .bl )
685
717
elif event == "Remove application" :
686
718
try :
687
719
self .bl .flashClear ()
688
- sg . popup (f'Successfully removed application' )
720
+ Popup (f'Successfully removed application' , self . window )
689
721
except Exception as ex :
690
- sg .popup (f"Couldn't remove application ({ ex } )" )
722
+ sg .popup (f"Couldn't remove application ({ ex } )" , self . window )
691
723
692
724
elif event .startswith ("_unique_configBtn" ):
693
725
self .window ['-COL1-' ].update (visible = False )
@@ -713,7 +745,7 @@ def run(self) -> None:
713
745
714
746
elif event == "recoveryMode" :
715
747
if recoveryMode (self .bl ):
716
- sg . Popup (f'Device successfully put into USB recovery mode.' )
748
+ Popup (f'Device successfully put into USB recovery mode.' , self . window )
717
749
# Device will reboot, close previous and reset GUI
718
750
self .closeDevice ()
719
751
self .resetGui ()
@@ -872,6 +904,12 @@ def resetGui(self):
872
904
self .window .Element ('commit' ).update ("-version-" )
873
905
self .window .Element ('devState' ).update ("-state-" )
874
906
907
+ # Move back to 'About' page
908
+ self .window ['-COL1-' ].update (visible = True )
909
+ self .window ['-COL2-' ].update (visible = False )
910
+ self .window ['-COL3-' ].update (visible = False )
911
+ self .window ['-COL4-' ].update (visible = False )
912
+
875
913
def closeDevice (self ):
876
914
if self .bl is not None :
877
915
self .bl .close ()
@@ -885,7 +923,7 @@ def getDevices(self):
885
923
deviceInfos = dai .XLinkConnection .getAllConnectedDevices ()
886
924
if not deviceInfos :
887
925
self .window .Element ('devices' ).update ("No devices" )
888
- sg .Popup ("No devices found." )
926
+ # sg.Popup("No devices found.")
889
927
else :
890
928
for deviceInfo in deviceInfos :
891
929
deviceTxt = deviceInfo .getMxId ()
@@ -896,7 +934,7 @@ def getDevices(self):
896
934
self .window .Element ('devices' ).update ("Select device" , values = listedDevices )
897
935
except Exception as ex :
898
936
PrintException ()
899
- sg . Popup (f'{ ex } ' )
937
+ Popup (f'{ ex } ' , window = self . window )
900
938
901
939
def flashConfig (self ):
902
940
values = self .values
@@ -912,22 +950,22 @@ def flashConfig(self):
912
950
try :
913
951
if self .isPoE :
914
952
if self .values ['staticBut' ]:
915
- if check_ip (values ['ip' ]) and check_ip (values ['mask' ]) and check_ip (values ['gateway' ], req = False ):
953
+ if check_ip (self . window , values ['ip' ]) and check_ip (self . window , values ['mask' ]) and check_ip (self . window , values ['gateway' ], req = False ):
916
954
conf .setStaticIPv4 (values ['ip' ], values ['mask' ], values ['gateway' ])
917
955
else :
918
956
raise Exception ('IP or Mask missing using static IP configuration' )
919
957
else :
920
- if check_ip (values ['ip' ], req = False ) and check_ip (values ['mask' ], req = False ) and check_ip (values ['gateway' ], req = False ):
958
+ if check_ip (self . window , values ['ip' ], req = False ) and check_ip (self . window , values ['mask' ], req = False ) and check_ip (self . window , values ['gateway' ], req = False ):
921
959
conf .setDynamicIPv4 (values ['ip' ], values ['mask' ], values ['gateway' ])
922
960
923
961
conf .setDnsIPv4 (values ['dns' ], values ['dnsAlt' ])
924
962
if values ['networkTimeout' ] != "" :
925
963
if int (values ['networkTimeout' ]) >= 0 :
926
964
conf .setNetworkTimeout (timedelta (seconds = int (values ['networkTimeout' ]) / 1000 ))
927
965
else :
928
- sg . Popup ("Values can not be negative!" )
966
+ Popup ("Values can not be negative!" , window = self . window )
929
967
if values ['mac' ] != "" :
930
- if check_mac (values ['mac' ]):
968
+ if check_mac (self . window , values ['mac' ]):
931
969
conf .setMacAddress (values ['mac' ])
932
970
else :
933
971
conf .setMacAddress ('00:00:00:00:00:00' )
@@ -936,29 +974,34 @@ def flashConfig(self):
936
974
if int (values ['usbTimeout' ]) >= 0 :
937
975
conf .setUsbTimeout (timedelta (seconds = int (values ['usbTimeout' ]) / 1000 ))
938
976
else :
939
- sg . Popup ("Values can not be negative!" )
977
+ Popup ("Values can not be negative!" , window = self . window )
940
978
if values ['usbSpeed' ] != "" :
941
979
conf .setUsbMaxSpeed (getattr (dai .UsbSpeed , values ['usbSpeed' ]))
942
980
943
981
success , error = self .bl .flashConfig (conf )
944
982
if not success :
945
- sg .Popup (f"Flashing failed: { error } " )
983
+ Popup (f"Flashing failed: { error } " , window = self .window )
984
+ return False
946
985
else :
947
- sg .Popup ("Flashing successful." )
986
+ Popup ("Flashing successful." , window = self .window )
987
+ return True
988
+
948
989
except Exception as ex :
949
990
PrintException ()
950
- sg .Popup (f'{ ex } ' )
991
+ Popup (f'{ ex } ' , window = self .window )
992
+
993
+ return None
951
994
952
995
def clearConfig (self ):
953
996
try :
954
997
success , error = self .bl .flashConfigClear ()
955
998
if not success :
956
- sg . Popup (f"Clearing configuration failed: { error } " )
999
+ Popup (f"Clearing configuration failed: { error } " , window = self . window )
957
1000
else :
958
- sg . Popup ("Successfully cleared configuration." )
1001
+ Popup ("Successfully cleared configuration." , window = self . window )
959
1002
except Exception as ex :
960
1003
PrintException ()
961
- sg . Popup (f'{ ex } ' )
1004
+ Popup (f'{ ex } ' , window = self . window )
962
1005
963
1006
964
1007
app = DeviceManager ()
0 commit comments