55
66from PyQt5 import QtCore , QtGui , QtWidgets
77import sys
8- import win32com .client
8+
9+ try :
10+ import ASCOM
11+ except ImportError :
12+ has_ASCOM = False
13+ else :
14+ has_ASCOM = True
15+
16+ import UART
917
1018import AutoSTAR_remote_ui
1119
12- version = "V1.0.1 "
20+ version = "V1.1.0 "
1321
14- theme_selection = "Dark" # "Dark", "Light"
15- LCD_polling_time = 1000 # milliseconds
16- LCD_earlyUpdate_time = 200 # milliseconds
22+ theme_selection = "Dark" # "Dark", "Light"
23+ LCD_polling_time = 1000 # milliseconds
24+ LCD_earlyUpdate_time = 200 # milliseconds
1725
1826"""
1927By watching the RS232 communication of the AutoStart Suit telescope control I found the following commands:
4957 + ? :EK63#
5058"""
5159
60+
5261class MainWin (QtWidgets .QMainWindow ):
5362 """
5463 AutoSTAR_remote main window.
@@ -63,9 +72,12 @@ def __init__(self):
6372 font .setStyleHint (QtGui .QFont .TypeWriter )
6473 font .setPointSizeF (10 )
6574 self .ui .plainTextEdit_LCD .setFont (font )
66- # states
67- self .Telescope = None
68- self .TelescopeName = ""
75+ self .ui .actionconnect_ASCOM .setEnabled (has_ASCOM )
76+ # communication interface
77+ self .Interface = None
78+ # persistent settings
79+ self .Settings = QtCore .QSettings ()
80+ print (f'QSettings file: { self .Settings .fileName ()} ' )
6981 # LCD polling timer
7082 self .PollingTimer = QtCore .QTimer ()
7183 self .PollingTimer .setSingleShot (True )
@@ -105,70 +117,71 @@ def __init__(self):
105117 self .ui .pushButton_FocOut .pressed .connect (lambda : self .sendCommandBlind ("F+" ))
106118 self .ui .pushButton_FocOut .released .connect (lambda : self .sendCommandBlind ("FQ" ))
107119
108-
109120 @QtCore .pyqtSlot ()
110121 def closeEvent (self , event ):
111122 self .PollingTimer .stop ()
112- if self .Telescope is not None :
113- if self .Telescope .Connected :
114- self .Telescope .Connected = False
123+ if self .Interface is not None :
124+ self .Interface .close ()
115125 # proceed with close
116126 event .accept ()
117127
128+ def update_GuiOpenInterface (self ):
129+ """ update GUI elements after opening interface
130+ """
131+ self .ui .statusbar .showMessage (self .Interface .Name )
132+ self .ui .actionconnect_ASCOM .setEnabled (False )
133+ self .ui .actionconnect_UART .setEnabled (False )
134+ self .ui .actiondisconnect .setEnabled (True )
135+ self .ui .centralwidget .setEnabled (True )
136+ if self .ui .actionpoll .isChecked ():
137+ if not self .PollingTimer .isActive ():
138+ self .PollingTimer .setInterval (LCD_earlyUpdate_time )
139+ self .PollingTimer .start ()
140+ self .ui .actionupdate_now .setEnabled (True )
141+
118142 @QtCore .pyqtSlot ()
119- def on_actionconnect_triggered (self ):
120- try :
121- Chooser = win32com .client .Dispatch ("ASCOM.Utilities.Chooser" )
122- except win32com .client .pywintypes .com_error :
123- QtWidgets .QMessageBox .critical (None , "Can not call ASCOM!" ,
124- f"Is ASCOM installed?" )
125- return
126- Chooser .DeviceType = 'Telescope'
127- self .TelescopeName = Chooser .Choose (None )
128- self .ui .statusbar .showMessage (self .TelescopeName )
129- self .Telescope = win32com .client .Dispatch (self .TelescopeName )
130- self .Telescope .Connected = True
131- if not self .Telescope .Connected :
132- QtWidgets .QMessageBox .critical (None , "Can not connect to telescope!" ,
133- f"Please check connection to\n { self .TelescopeName } .\n Maybe it is already in use." )
143+ def on_actionconnect_ASCOM_triggered (self ):
144+ self .Interface = ASCOM .ASCOM ()
145+ self .Interface .open ()
146+ if self .Interface .is_open ():
147+ self .update_GuiOpenInterface ()
134148 else :
135- self .ui .actionconnect .setEnabled (False )
136- self .ui .actiondisconnect .setEnabled (True )
137- self .ui .centralwidget .setEnabled (True )
138- if self .ui .actionpoll .isChecked ():
139- if not self .PollingTimer .isActive ():
140- self .PollingTimer .setInterval (LCD_earlyUpdate_time )
141- self .PollingTimer .start ()
142- self .ui .actionupdate_now .setEnabled (True )
149+ self .Interface .close ()
150+ self .Interface = None
151+
152+ @QtCore .pyqtSlot ()
153+ def on_actionconnect_UART_triggered (self ):
154+ Parameter = {k : self .Settings .value (k ) for k in self .Settings .allKeys ()}
155+ self .Interface = UART .UART (Parameter = Parameter )
156+ self .Interface .open ()
157+ if self .Interface .is_open ():
158+ print ("DBG: UART is open" )
159+ self .update_GuiOpenInterface ()
160+ else :
161+ self .Interface .close ()
162+ self .Interface = None
143163
144164 @QtCore .pyqtSlot ()
145165 def on_actiondisconnect_triggered (self ):
146166 self .PollingTimer .stop ()
147- if self .Telescope is not None :
148- if self .Telescope .Connected :
149- self .Telescope .Connected = False
150- self .ui .actionconnect .setEnabled (True )
151- self .ui .actiondisconnect .setEnabled (False )
152- self .ui .centralwidget .setEnabled (False )
153- self .ui .actionupdate_now .setEnabled (False )
154-
155- def sendAction (self , param ):
156- if self .Telescope is not None :
157- if self .Telescope .Connected :
158- return self .Telescope .Action ("handbox" , param )
159- return None
167+ if self .Interface is not None :
168+ Parameter = self .Interface .get_Parameter ()
169+ for k , v in Parameter .items ():
170+ self .Settings .setValue (k , v )
171+ self .Settings .sync ()
172+ self .Interface .close ()
173+ self .Interface = None
174+ self .ui .actionconnect_ASCOM .setEnabled (has_ASCOM )
175+ self .ui .actionconnect_UART .setEnabled (True )
176+ self .ui .actiondisconnect .setEnabled (False )
177+ self .ui .centralwidget .setEnabled (False )
178+ self .ui .actionupdate_now .setEnabled (False )
160179
161180 def sendCommandBlind (self , cmd ):
162- if self .Telescope is not None :
163- if self .Telescope .Connected :
164- try :
165- ret = self .Telescope .CommandBlind (cmd , False )
166- except win32com .client .pywintypes .com_error as e :
167- print (f'sendCommandBlind: { e } ' )
168- return None
169- else :
170- return ret
171- return None
181+ if self .Interface is not None :
182+ return self .Interface .sendCommandBlind (cmd )
183+ else :
184+ return None
172185
173186 def buttonAction (self , cmd , long_cmd = None ):
174187 """
@@ -192,40 +205,35 @@ def buttonAction(self, cmd, long_cmd=None):
192205 # with a translation table:
193206 CharacterTranslationTable = {
194207 0x0d : ord ('\n ' ),
195- #0x2020: ord(' '),
208+ # 0x2020: ord(' '),
196209 0xDF : ord ('°' ),
197- 0x7E : 0x2192 , # ord('>'),
198- 0x7F : 0x2190 , # ord('<'),
199- 0x18 : 0x2191 , # ord('^'),
200- 0x19 : 0x2193 , # ord('v'),
210+ 0x7E : 0x2192 , # ord('>'),
211+ 0x7F : 0x2190 , # ord('<'),
212+ 0x18 : 0x2191 , # ord('^'),
213+ 0x19 : 0x2193 , # ord('v'),
201214 # bar graph symbols
202215 0x5F : 0x2582 ,
203216 0x81 : 0x2583 ,
204- 0x201A : 0x2584 , # raw: 0x82
205- 0x0192 : 0x2585 , # raw: 0x83
206- 0x201E : 0x2586 , # raw: 0x84
207- 0x2026 : 0x2587 , # raw: 0x85
208- 0x2020 : 0x2588 , # raw: 0x86
217+ 0x201A : 0x2584 , # raw: 0x82
218+ 0x0192 : 0x2585 , # raw: 0x83
219+ 0x201E : 0x2586 , # raw: 0x84
220+ 0x2026 : 0x2587 , # raw: 0x85
221+ 0x2020 : 0x2588 , # raw: 0x86
209222 }
210223
211224 def updateLCD (self ):
212- try :
213- LcdText = self .Telescope .CommandString ("ED" , False )
214- except win32com .client .pywintypes .com_error as e :
215- # Sometimes the handbox needs long time for calculations and does not
216- # send the LCD contents bfore the ASCOM driver trows a timeout exception.
217- # Here we catch these timeout exceptions.
218- print (f'updateLCD: { e } ' )
219- LcdText = None
225+ LcdText = None
226+ if self .Interface is not None :
227+ LcdText = self .Interface .sendCommandString ("ED" )
220228 if LcdText is not None :
221229 LcdText = LcdText .translate (self .CharacterTranslationTable )
222230 Unknown = ord (LcdText [0 ])
223231 Line1 = LcdText [1 :17 ]
224232 Line2 = LcdText [17 :]
225233 self .ui .plainTextEdit_LCD .setPlainText (f'{ Line1 } \n { Line2 } ' )
226- #print(f'{Unknown}: >{Line1}< >{Line2}<')
227- #print(", ".join([f'{ord(c):02X}' for c in LcdText]))
228- #print(bytes(LcdText, 'utf-8'))
234+ # print(f'{Unknown}: >{Line1}< >{Line2}<')
235+ # print(", ".join([f'{ord(c):02X}' for c in LcdText]))
236+ # print(bytes(LcdText, 'utf-8'))
229237 if self .ui .actionpoll .isChecked ():
230238 if not self .PollingTimer .isActive ():
231239 self .PollingTimer .setInterval (LCD_polling_time )
@@ -245,15 +253,15 @@ def on_actionpoll_toggled(self, isChecked):
245253 self .PollingTimer .stop ()
246254
247255
248- ## Start Qt event loop unless running in interactive mode.
256+ # Start Qt event loop unless running in interactive mode.
249257def main ():
250258 # build application
251259 App = QtWidgets .QApplication (sys .argv )
252260 App .setOrganizationName ("GeierSoft" )
253261 App .setOrganizationDomain ("Astro" )
254262 App .setApplicationName ("AutoSTAR_remote" )
255263 #
256- # stolen from https://stackoverflow.com/questions/48256772/dark-theme-for-qt-widgets
264+ # copied from https://stackoverflow.com/questions/48256772/dark-theme-for-qt-widgets
257265 if theme_selection == 'Dark' :
258266 App .setStyle ("Fusion" )
259267 #
@@ -285,12 +293,11 @@ def main():
285293 pass
286294 #
287295 MainWindow = MainWin ()
288- #MainWindow.resize(1400, 900)
296+ # MainWindow.resize(1400, 900)
289297 MainWindow .show ()
290298 if (sys .flags .interactive != 1 ) or not hasattr (QtCore , 'PYQT_VERSION' ):
291- #QtGui.QApplication.instance().exec_()
292299 sys .exit (App .exec_ ())
293300
294301
295302if __name__ == '__main__' :
296- main ()
303+ main ()
0 commit comments