Пример #1
0
class Weather(QtCore.QThread):
    logger = logging.getLogger(__name__)  # get logger for  problems
    signalWeatherData = QtCore.pyqtSignal(
        [dict], name='weatherData')  # single for data transfer to gui
    signalWeatherConnected = QtCore.pyqtSignal(
        [int], name='weatherConnected')  # signal for connection status

    def __init__(self, app):
        super().__init__()
        self.app = app
        self.connected = 2
        self.ascom = None  # placeholder for ascom driver object
        self.chooser = None  # placeholder for ascom chooser object
        self.driverName = ''  # driver object name
        self.slewing = False
        self.counter = 0

    def run(self):  # runnable for doing the work
        pythoncom.CoInitialize()  # needed for doing CO objects in threads
        self.connected = 0  # set connection flag for stick itself
        self.counter = 0
        while True:  # main loop for stick thread
            self.signalWeatherConnected.emit(
                self.connected)  # send status to GUI
            if self.connected == 1:  # differentiate between dome connected or not
                if self.counter == 0:  # jobs once done at the beginning
                    self.getStatusOnce()  # task once
                if self.counter % 2 == 0:  # all tasks with 200 ms
                    self.getStatusFast()  # polling the mount status Ginfo
                if self.counter % 20 == 0:  # all tasks with 3 s
                    self.getStatusMedium()  # polling the mount
                if self.counter % 300 == 0:  # all task with 1 minute
                    self.getStatusSlow()  # slow ones
                self.counter += 1  # increasing counter for selection
                time.sleep(.1)
            else:
                try:
                    if self.driverName == '':
                        self.connected = 2
                    else:
                        self.ascom = Dispatch(self.driverName)  # load driver
                        self.ascom.connected = True
                        self.connected = 1  # set status to connected
                        self.logger.debug(
                            'run            -> driver chosen:{0}'.format(
                                self.driverName))
                except Exception as e:  # if general exception
                    if self.driverName != '':
                        self.logger.error(
                            'run Weather    -> general exception: {0}'.format(
                                e))  # write to logger
                    if self.driverName == '':
                        self.connected = 2
                    else:
                        self.connected = 0  # run the driver setup dialog
                finally:  # still continua and try it again
                    pass  # needed for continue
                time.sleep(1)  # wait for the next cycle
        self.ascom.Quit()
        pythoncom.CoUninitialize()  # needed for doing COm objects in threads
        self.terminate()  # closing the thread at the end

    def __del__(self):  # remove thread
        self.wait()

    def getStatusFast(self):
        pass

    def getStatusMedium(self):
        data = dict()
        try:
            data['DewPoint'] = self.ascom.DewPoint
            data['Temperature'] = self.ascom.Temperature
            data['Humidity'] = self.ascom.Humidity
            data['Pressure'] = self.ascom.Pressure
            data['CloudCover'] = self.ascom.CloudCover
            data['RainRate'] = self.ascom.RainRate
            data['WindSpeed'] = self.ascom.WindSpeed
            data['WindDirection'] = self.ascom.WindDirection
            self.signalWeatherData.emit(data)  # send data
        except Exception as e:
            self.logger.error(
                'getStatusMedium-> error accessing weather ascom data: {}'.
                format(e))

    def getStatusSlow(self):
        pass

    def getStatusOnce(self):
        pass

    def setupDriver(self):  #
        try:
            self.chooser = Dispatch('ASCOM.Utilities.Chooser')
            self.chooser.DeviceType = 'ObservingConditions'
            self.driverName = self.chooser.Choose(self.driverName)
            self.logger.debug('setupDriverWeat-> driver chosen:{0}'.format(
                self.driverName))
            if self.driverName == '':
                self.connected = 2
            else:
                self.connected = 0  # run the driver setup dialog
        except Exception as e:  # general exception
            self.app.messageQueue.put(
                'Driver Exception in setupWeather')  # write to gui
            self.logger.error(
                'setupWeather    -> general exception:{0}'.format(
                    e))  # write to log
            if self.driverName == '':
                self.connected = 2
            else:
                self.connected = 0  # run the driver setup dialog
        finally:  # continue to work
            pass  # python necessary
Пример #2
0
class Dome(QtCore.QThread):
    # signals for communication to main Thread / GUI
    logger = logging.getLogger(__name__)
    signalDomeConnected = QtCore.pyqtSignal([int], name='domeConnected')
    signalDomPointer = QtCore.pyqtSignal([float], name='domePointer')

    def __init__(self, app):
        super().__init__()
        self.app = app
        self.connected = 2
        self.ascom = None  # placeholder for ascom driver object
        self.chooser = None  # placeholder for ascom chooser object
        self.driverName = ''  # driver object name
        self.slewing = False
        self.counter = 0

    def run(self):  # runnable for doing the work
        pythoncom.CoInitialize()  # needed for doing CO objects in threads
        self.connected = 0  # set connection flag for stick itself
        self.counter = 0
        while True:  # main loop for stick thread
            self.signalDomeConnected.emit(self.connected)  # send status to GUI
            if self.connected == 1:  # differentiate between dome connected or not
                if self.counter == 0:  # jobs once done at the beginning
                    self.getStatusOnce()  # task once
                if self.counter % 2 == 0:  # all tasks with 200 ms
                    self.getStatusFast()  # polling the mount status Ginfo
                if self.counter % 20 == 0:  # all tasks with 3 s
                    self.getStatusMedium()  # polling the mount
                if self.counter % 300 == 0:  # all task with 1 minute
                    self.getStatusSlow()  # slow ones
                self.counter += 1  # increasing counter for selection
                time.sleep(.1)
            else:
                try:
                    if self.driverName == '':
                        self.connected = 2
                    else:
                        self.ascom = Dispatch(self.driverName)  # load driver
                        self.ascom.connected = True
                        self.connected = 1  # set status to connected
                        self.logger.debug(
                            'run            -> driver chosen:{0}'.format(
                                self.driverName))
                except Exception as e:  # if general exception
                    if self.driverName != '':
                        self.logger.error(
                            'run Dome       -> general exception: {0}'.format(
                                e))  # write to logger
                    if self.driverName == '':
                        self.connected = 2
                    else:
                        self.connected = 0  # run the driver setup dialog
                finally:  # still continua and try it again
                    pass  # needed for continue
                time.sleep(1)  # wait for the next cycle
        self.ascom.Quit()
        pythoncom.CoUninitialize()  # needed for doing COm objects in threads
        self.terminate()  # closing the thread at the end

    def __del__(self):  # remove thread
        self.wait()  #

    def getStatusFast(self):
        self.slewing = self.ascom.Slewing
        self.signalDomPointer.emit(self.ascom.Azimuth)

    def getStatusMedium(self):
        pass

    def getStatusSlow(self):
        pass

    def getStatusOnce(self):
        pass

    def setupDriver(self):  #
        try:
            self.chooser = Dispatch('ASCOM.Utilities.Chooser')
            self.chooser.DeviceType = 'Dome'
            self.driverName = self.chooser.Choose(self.driverName)
            self.logger.debug('setupDriverDome -> driver chosen:{0}'.format(
                self.driverName))
            if self.driverName == '':
                self.connected = 2
            else:
                self.connected = 0  # run the driver setup dialog
        except Exception as e:  # general exception
            self.app.messageQueue.put(
                'Driver Exception in setupDome')  # write to gui
            self.logger.error(
                'setupDriverDome -> general exception:{0}'.format(
                    e))  # write to log
            if self.driverName == '':
                self.connected = 2
            else:
                self.connected = 0  # run the driver setup dialog
        finally:  # continue to work
            pass  # python necessary
Пример #3
0
class Mount(QtCore.QThread):
    logger = logging.getLogger(__name__)  # enable logging
    signalMountConnected = QtCore.pyqtSignal(
        [bool], name='mountConnected')  # signal for connection status
    signalMountAzAltPointer = QtCore.pyqtSignal([float, float],
                                                name='mountAzAltPointer')
    signalMountTrackPreview = QtCore.pyqtSignal(name='mountTrackPreview')

    BLUE = 'background-color: rgb(42, 130, 218)'
    DEFAULT = 'background-color: rgb(32,32,32); color: rgb(192,192,192)'

    def __init__(self, app):
        super().__init__()  # init of the class parent with super
        self.app = app  # accessing ui object from mount class

        self.statusReference = {
            '0': 'Tracking',
            '1': 'Stopped after STOP',
            '2': 'Slewing to park position',
            '3': 'Unparking',
            '4': 'Slewing to home position',
            '5': 'Parked',
            '6': 'Slewing or going to stop',
            '7': 'Tracking Off no move',
            '8': 'Motor low temperature',
            '9': 'Tracking outside limits',
            '10': 'Following Satellite',
            '11': 'User OK Needed',
            '98': 'Unknown Status',
            '99': 'Error'
        }  # conversion list Gstat to text
        self.ra = 0  # mount reported ra to J2000 converted
        self.dec = 0  # mount reported dec to J2000 converted
        self.raJnow = 0
        self.decJnow = 0
        self.az = 0  # mount reported azimuth
        self.alt = 0  # mount reported altitude
        self.stat = 0  # mount status (from Gstat command)
        self.slewing = False  # from *D' command
        self.site_lat = 49  # site lat
        self.site_lon = 0  # site lon
        self.site_height = 0  # site height
        self.jd = 2451544.5  # julian date
        self.sidereal_time = ''  # local sidereal time
        self.pierside = 0  # side of pier (E/W)
        self.timeToFlip = '200'  # minutes to flip
        self.refractionTemp = '20.0'  # coordinate transformation need temp
        self.refractionPressure = '900.0'  # and pressure
        self.transform = None  # ascom novas library entry point
        self.ascom = None  # ascom mount driver entry point
        self.mountAlignRMSsum = 0  # variable for counting RMS over stars
        self.mountAlignmentPoints = []  # alignment point for modeling
        self.mountAlignNumberStars = 0  # number of stars
        self.counter = 0  # counter im main loop
        self.connected = False  # connection status
        self.transformConnected = False
        self.driverName = 'ASCOM.FrejvallGM.Telescope'  # default driver name is Per's driver
        self.chooser = None  # object space
        self.driver_real = False  # identifier, if data is real (or simulation
        self.value_azimuth = 0.0  # object for Sz command
        self.value_altitude = 0.0  # object for Sa command
        self.transformationLock = threading.Lock(
        )  # locking object for single access to ascom transformation object
        self.sendCommandLock = threading.Lock()

    def run(self):  # runnable of the thread
        pythoncom.CoInitialize()  # needed for doing COM objects in threads
        try:  # start accessing a com object
            self.transform = Dispatch(
                'ASCOM.Astrometry.Transform.Transform'
            )  # novas library for Jnow J2000 conversion through ASCOM
            self.transformConnected = True
        except Exception as e:  # exception handling
            self.app.messageQueue.put(
                'Error loading ASCOM transform Driver')  # write to gui
            self.logger.error(
                'run Mount      -> loading ASCOM transform error:{0}'.format(
                    e))  # write logfile
        finally:  # we don't stop on error the wizzard
            pass  # python specific
        self.connected = False  # init of connection status
        self.counter = 0  # init count for managing different cycle times
        while True:  # main loop in thread
            self.signalMountConnected.emit(
                self.connected)  # sending the connection status
            if self.connected:  # when connected, starting the work
                if not self.app.commandQueue.empty(
                ):  # checking if in queue is something to do
                    command = self.app.commandQueue.get(
                    )  # if yes, getting the work command
                    if command == 'GetAlignmentModel':  # checking which command was sent
                        self.app.ui.btn_getActualModel.setStyleSheet(self.BLUE)
                        self.getAlignmentModel(
                        )  # running the appropriate method
                        self.app.ui.btn_getActualModel.setStyleSheet(
                            self.DEFAULT)
                    elif command == 'ClearAlign':
                        self.sendCommand('delalig')
                    elif command == 'RunTargetRMSAlignment':
                        self.app.ui.btn_runTargetRMSAlignment.setStyleSheet(
                            self.BLUE)
                        self.runTargetRMSAlignment()
                        self.app.ui.btn_runTargetRMSAlignment.setStyleSheet(
                            self.DEFAULT)
                    elif command == 'DeleteWorstPoint':
                        self.app.ui.btn_deleteWorstPoint.setStyleSheet(
                            self.BLUE)
                        self.deleteWorstPoint()
                        self.app.ui.btn_deleteWorstPoint.setStyleSheet(
                            self.DEFAULT)
                    elif command == 'BackupModel':
                        self.app.ui.btn_backupModel.setStyleSheet(
                            self.BLUE)  # button blue
                        self.backupModel()
                        self.app.ui.btn_backupModel.setStyleSheet(
                            self.DEFAULT)  # button to default back
                    elif command == 'RestoreModel':
                        self.app.ui.btn_restoreModel.setStyleSheet(self.BLUE)
                        self.restoreModel()
                        self.app.ui.btn_restoreModel.setStyleSheet(
                            self.DEFAULT)
                    elif command == 'LoadSimpleModel':
                        self.app.ui.btn_loadSimpleModel.setStyleSheet(
                            self.BLUE)
                        self.loadSimpleModel()
                        self.app.ui.btn_loadSimpleModel.setStyleSheet(
                            self.DEFAULT)
                    elif command == 'SaveSimpleModel':
                        self.app.ui.btn_saveSimpleModel.setStyleSheet(
                            self.BLUE)
                        self.saveSimpleModel()
                        self.app.ui.btn_saveSimpleModel.setStyleSheet(
                            self.DEFAULT)
                    elif command == 'SetRefractionParameter':
                        self.setRefractionParameter()
                    elif command == 'FLIP':
                        self.flipMount()
                    else:
                        self.sendCommand(
                            command
                        )  # doing the command directly to mount (no method necessary)
                    self.app.commandQueue.task_done()
                else:  # if not connected, the we should do this
                    if self.counter == 0:  # jobs once done at the beginning
                        self.getStatusOnce()  # task once
                    if self.counter % 2 == 0:  # all tasks with 400 ms
                        self.getStatusFast()  # polling the mount status Ginfo
                    if self.counter % 15 == 0:  # all tasks with 3 s
                        self.getStatusMedium()  # polling the mount
                    if self.counter % 150 == 0:  # all task with 30 seconds
                        self.getStatusSlow()  # slow ones
                time.sleep(0.2)  # time base is 200 ms
                self.counter += 1  # increasing counter for selection
            else:  # when not connected try to connect
                try:
                    self.ascom = Dispatch(
                        self.driverName)  # select win32 driver
                    if self.driverName == 'ASCOM.FrejvallGM.Telescope':  # identify real telescope against simulator
                        self.driver_real = True  # set it
                    else:
                        self.driver_real = False  # set it
                    self.ascom.connected = True  # connect to mount
                    self.connected = True  # setting connection status from driver
                    self.counter = 0  # whenever reconnect, then start from scratch
                except Exception as e:  # error handling
                    if self.driverName != '':  # if driver is not empty, than error messages
                        self.logger.error(
                            'run Mount      -> Driver COM Error in dispatchMount: {0}'
                            .format(e))  # to logger
                    self.connected = False  # connection broken
                finally:  # we don't stop, but try it again
                    time.sleep(1)  # try it every second, not more
        self.ascom.Quit()  # close ascom mount object
        self.transform.Quit()  # close ascom novas transform object
        pythoncom.CoUninitialize()  # needed for doing COM objects in threads
        self.terminate()  # closing the thread at the end

    def __del__(self):  # remove thread
        self.wait()  # wait for stop of thread

    def sendCommand(self,
                    command):  # core routine for sending commands to mount
        reply = ''  # reply is empty
        self.sendCommandLock.acquire()
        if self.driver_real:
            try:  # all with error handling
                if command in [
                        'AP', 'hP', 'PO', 'RT0', 'RT1', 'RT2', 'RT9', 'STOP',
                        'U2'
                ]:  # these are the commands, which do not expect a return value
                    self.ascom.CommandBlind(command)  # than do blind command
                else:  #
                    reply = self.ascom.CommandString(
                        command)  # with return value do regular command
            except pythoncom.com_error as e:  # error handling
                self.app.messageQueue.put(
                    'Driver COM Error in sendCommand')  # gui
                self.logger.error(
                    'sendCommand Mount -> error: {0} command:{1}  reply:{2} '.
                    format(e, command, reply))  # logger
                self.connected = False  # in case of error, the connection might be broken
            finally:  # we don't stop
                if len(reply) > 0:  # if there is a reply
                    value = reply.rstrip('#').strip()  # return the value
                    if command == 'CMS':
                        self.logger.debug(
                            'sendCommand    -> Return Value Add Model Point: {0}'
                            .format(reply))
                else:  #
                    value = ''  # nothing
            self.sendCommandLock.release()
            return value
        else:  # from here we doing the simulation for 10micron mounts commands
            value = ''
            if command == 'Gev':  # which are special, but only for the most important for MW to run
                value = str(self.ascom.SiteElevation)
            elif command == 'Gmte':
                value = '0125'
            elif command == 'Gt':
                value = self.decimalToDegree(self.ascom.SiteLatitude, True,
                                             False)
            elif command == 'Gg':
                lon = self.decimalToDegree(self.ascom.SiteLongitude, True,
                                           False)
                if lon[0] == '-':  # due to compatibility to LX200 protocol east is negative
                    lon1 = lon.replace('-', '+')  # change that
                else:
                    lon1 = lon.replace('+', '-')  # and vice versa
                value = lon1
            elif command.startswith('Sz'):
                self.value_azimuth = float(
                    command[2:5]) + float(command[6:8]) / 60
            elif command.startswith('Sa'):
                self.value_altitude = float(
                    command[2:5]) + float(command[6:8]) / 60
            elif command == 'MS':
                self.ascom.Tracking = False
                self.ascom.SlewToAltAzAsync(self.value_azimuth,
                                            self.value_altitude)
                self.ascom.Tracking = True
            elif command == 'MA':
                self.ascom.Tracking = False
                self.ascom.SlewToAltAzAsync(self.value_azimuth,
                                            self.value_altitude)
                self.ascom.Tracking = False
            elif command == 'GS':
                value = self.decimalToDegree(self.ascom.SiderealTime, False,
                                             False)
            elif command == 'GRTMP':
                value = '10.0'
            elif command == 'Ginfo':
                self.raJnow = self.ascom.RightAscension
                self.decJnow = self.ascom.Declination
                az = self.ascom.Azimuth
                alt = self.ascom.Altitude
                if self.ascom.Slewing:
                    stat = 6
                else:
                    if self.ascom.Tracking:
                        stat = 0
                    else:
                        stat = 7
                jd = self.ascom.SiderealTime + 2440587.5
                if self.ascom.SideOfPier == 0:
                    pierside = 'E'
                else:
                    pierside = 'W'
                if self.ascom.Slewing:
                    slew = 1
                else:
                    slew = 0
                value = '{0},{1},{2},{3},{4},{5},{6},{7}#'.format(
                    self.raJnow, self.decJnow, pierside, az, alt, jd, stat,
                    slew)
            elif command == 'PO':
                self.ascom.Unpark()
            elif command == 'hP':
                self.ascom.Park()
            elif command == 'AP':
                self.ascom.Tracking = True
            elif command == 'RT9':
                self.ascom.Tracking = False
            elif command == 'GTMP1':
                value = '10.0'
            elif command == 'GRPRS':
                value = '990.0'
            elif command == 'Guaf':
                value = '0'
            elif command == 'GMs':
                value = '15'
            elif command == 'Gh':
                value = '90'
            elif command == 'Go':
                value = '00'
            elif command == 'Gdat':
                value = '0'
            elif command in ['GVD', 'GVN', 'GVP', 'GVT', 'GVZ']:
                value = 'Simulation'
            elif command == 'GREF':
                value = '1'
            elif command == 'CMS':
                value = 'V'
            elif command == 'getalst':
                value = '0'
            else:
                pass
        self.sendCommandLock.release()
        return value

    def transformNovas(
            self,
            ra,
            dec,
            transform=1):  # wrapper for the novas ascom implementation
        self.transformationLock.acquire(
        )  # which is not threat safe, so we have to do this
        self.transform.SiteTemperature = float(
            self.refractionTemp)  # needs refraction temp
        if transform == 1:  # 1 = J2000 -> alt/az
            if ra < 0:  # ra has to be between 0 and 23,99999
                ra += 24  #
            if ra >= 24:  # so set it right
                ra -= 24
            self.transform.SetJ2000(ra, dec)  # set J2000 ra, dec
            val1 = self.transform.AzimuthTopocentric  # convert az
            val2 = self.transform.ElevationTopocentric  # convert alt
        elif transform == 2:  # 2 = Jnow -> J2000
            self.transform.SetTopocentric(ra, dec)  # set Jnow data
            val1 = self.transform.RAJ2000
            val2 = self.transform.DECJ2000
        elif transform == 3:  # 3 = J2000 -> JNow
            self.transform.SetJ2000(ra, dec)  # set J2000 data
            val1 = self.transform.RATopocentric
            val2 = self.transform.DECTopocentric
        elif transform == 4:  # 1 = JNow -> alt/az
            if ra < 0:  # ra has to be between 0 and 23,99999
                ra += 24  #
            if ra >= 24:  # so set it right
                ra -= 24
            self.transform.SetTopocentric(ra, dec)  # set JNow ra, dec
            val1 = self.transform.AzimuthTopocentric  # convert az
            val2 = self.transform.ElevationTopocentric  # convert alt
        else:
            val1 = ra
            val2 = dec
        self.transformationLock.release()  # release locking for thread safety
        return val1, val2

    def flipMount(self):  # doing the flip of the mount
        reply = self.sendCommand('FLIP').rstrip('#').strip()
        if reply == '0':  # error handling if not successful
            self.app.messageQueue.put(
                'Flip Mount could not be executed !')  # write to gui
            self.logger.debug('flipMount      -> error: {0}'.format(
                reply))  # write to logger

    def ra_dec_lst_to_az_alt(self, ra, dec, lst):
        LAT = self.site_lat
        HA = (lst - ra) * 15
        if HA >= 360:
            HA -= 360
        elif HA <= 0:
            HA += 360
        alt = math.asin(
            math.sin(dec) * math.sin(LAT) +
            math.cos(dec) * math.cos(LAT) * math.cos(HA))
        A = math.acos((math.sin(dec) - math.sin(alt) * math.sin(LAT)) /
                      (math.cos(alt) * math.cos(LAT)))
        if math.sin(HA) < 0:
            az = 360 - A
        else:
            az = A
        return az, alt

    def degStringToDecimal(
        self,
        value,
        splitter=':'
    ):  # conversion between Strings formats and decimal representation
        sign = 1
        if '-' in value:
            value = value.replace('-', '')
            sign = -1
        elif '+' in value:
            value = value.replace('+', '')
        try:
            if len(value.split(splitter)) == 3:
                hour, minute, second = value.split(splitter)
                return (float(hour) + float(minute) / 60 +
                        float(second) / 3600) * sign
            elif len(value.split(splitter)) == 2:
                hour, minute = value.split(splitter)
                return (float(hour) + float(minute) / 60) * sign
        except Exception as e:
            self.logger.error(
                'degStringToDeci-> error in conversion of:{0} with splitter:{1}, e:{2}'
                .format(value, splitter, e))
            return 0

    @staticmethod
    def decimalToDegree(
            value,
            with_sign,
            with_decimal,
            spl=':'):  # format decimal value to string in degree format
        if value >= 0:
            sign = '+'
        else:
            sign = '-'
        value = abs(value)
        hour = int(value)
        minute = int((value - hour) * 60)
        second = int(((value - hour) * 60 - minute) * 60)
        if with_decimal:
            second_dec = '.{0:1d}'.format(
                int((((value - hour) * 60 - minute) * 60 - second) * 10))
        else:
            second_dec = ''
        if with_sign:
            return '{0}{1:02d}{5}{2:02d}{5}{3:02d}{4}'.format(
                sign, hour, minute, second, second_dec, spl)
        else:
            return '{0:02d}{4}{1:02d}{4}{2:02d}{3}'.format(
                hour, minute, second, second_dec, spl)

    def getAlignmentModel(self):  # download alignment model from mount
        self.app.mountDataQueue.put({
            'Name': 'ModelStarError',
            'Value': 'delete'
        })  # clear the window in gui
        self.mountAlignRMSsum = 0  # set RMS sum to 0 for calculation
        self.mountAlignmentPoints = []  # clear the alignment points downloaded
        self.mountAlignNumberStars = int(
            self.sendCommand('getalst').rstrip(
                '#').strip())  # get number of stars
        if self.mountAlignNumberStars == 0:  # if no stars, finish
            return False
        for i in range(1, self.mountAlignNumberStars +
                       1):  # otherwise download them step for step
            try:
                reply = self.sendCommand('getalp{0:d}'.format(i)).split(',')
            except pythoncom.com_error as e:
                self.app.messageQueue.put(
                    'Driver COM Error in sendCommand {0}'.format(e))
                return False
            ha = reply[0].strip().split('.')[0]
            dec = reply[1].strip().split('.')[0]
            errorRMS = float(reply[2].strip())
            errorAngle = reply[3].strip().rstrip('#')
            self.mountAlignRMSsum += errorRMS**2
            self.mountAlignmentPoints.append((i, errorRMS))
            dec = dec.replace('*', ':')
            self.app.mountDataQueue.put({
                'Name':
                'ModelStarError',
                'Value':
                '#{0:02d} HA: {1} DEC: {2} Err: {3:4.1f}\x22 EA: {4:3s}\xb0\n'.
                format(i, ha, dec, errorRMS, errorAngle)
            })
        self.app.mountDataQueue.put({
            'Name': 'NumberAlignmentStars',
            'Value': self.mountAlignNumberStars
        })  # write them to gui
        self.app.mountDataQueue.put({
            'Name':
            'ModelRMSError',
            'Value':
            '{0:3.1f}'.format(
                math.sqrt(self.mountAlignRMSsum / self.mountAlignNumberStars))
        })  # set the error values in gui
        return True

    def runTargetRMSAlignment(self):
        if not self.getAlignmentModel():
            return
        self.mountAlignRMSsum = 999.9  # set maximum
        self.mountAlignNumberStars = 4  # set minimum for stars
        while math.sqrt(self.mountAlignRMSsum / self.mountAlignNumberStars) > float(self.app.ui.targetRMS.value()) \
                and self.mountAlignNumberStars > 3:
            a = sorted(self.mountAlignmentPoints,
                       key=itemgetter(1),
                       reverse=True)  # index 0 ist the worst star
            try:  # delete the worst star
                self.sendCommand('delalst{0:d}'.format(a[0][0]))
            except pythoncom.com_error as e:
                self.app.messageQueue.put(
                    'Driver COM Error in sendCommand {0}'.format(e))
            self.getAlignmentModel()

    def deleteWorstPoint(self):
        if not self.getAlignmentModel():
            return
        self.mountAlignRMSsum = 999.9  # set maximum
        self.mountAlignNumberStars = 4  # set minimum for stars
        if self.mountAlignNumberStars > 3:
            a = sorted(self.mountAlignmentPoints,
                       key=itemgetter(1),
                       reverse=True)  # index 0 ist the worst star
            try:  # delete the worst star
                self.sendCommand('delalst{0:d}'.format(a[0][0]))
            except pythoncom.com_error as e:
                self.app.messageQueue.put(
                    'Driver COM Error in sendCommand {0}'.format(e))
            self.getAlignmentModel()

    def saveActualModel(self, target):
        self.sendCommand('modeldel0' + target)
        reply = self.sendCommand('modelsv0' + target)
        if reply == '1':
            return True
        else:
            return False

    def loadActualModel(self, target):
        reply = self.sendCommand('modelld0' + target)
        if reply == '1':
            return True
        else:
            return False

    def backupModel(self):
        if self.saveActualModel('BACKUP'):
            self.app.messageQueue.put('Actual Model save to BACKUP')
        else:
            self.logger.debug(
                'backupModel    -> Model BACKUP could not be saved')  # log it

    def restoreModel(self):
        if self.loadActualModel('BACKUP'):
            self.app.messageQueue.put('Actual Model loaded from BACKUP')
        else:
            self.app.messageQueue.put(
                'There is no model named BACKUP or error while loading')
            self.logger.debug(
                'backupModel    -> Model BACKUP could not be loaded')  # log it

    def saveSimpleModel(self):
        if self.saveActualModel('SIMPLE'):
            self.app.messageQueue.put('Actual Model save to SIMPLE')
        else:
            self.logger.debug(
                'saveSimpleModel-> Model SIMPLE could not be saved')  # log it

    def loadSimpleModel(self):
        if self.loadActualModel('SIMPLE'):
            self.app.messageQueue.put('Actual Model loaded from SIMPLE')
        else:
            self.app.messageQueue.put(
                'There is no model named SIMPLE or error while loading')
            self.logger.debug(
                'loadSimpleModel-> Model SIMPLE could not be loaded')  # log it

    def setRefractionParameter(self):
        if self.app.ui.le_pressureStick.text() != '':  # value must be there
            self.sendCommand('SRPRS{0:04.1f}'.format(
                float(self.app.ui.le_pressureStick.text())))
            if float(self.app.ui.le_temperatureStick.text()) > 0:
                self.sendCommand('SRTMP+{0:03.1f}'.format(
                    float(self.app.ui.le_temperatureStick.text())))
            else:
                self.sendCommand('SRTMP-{0:3.1f}'.format(
                    -float(self.app.ui.le_temperatureStick.text())))
            self.app.mountDataQueue.put({
                'Name': 'GetRefractionTemperature',
                'Value': self.sendCommand('GRTMP')
            })
            self.app.mountDataQueue.put({
                'Name': 'GetRefractionPressure',
                'Value': self.sendCommand('GRPRS')
            })

    def getStatusFast(self):  # fast status item like pointing
        reply = self.sendCommand('GS')
        if reply:
            self.sidereal_time = reply.strip('#')
            self.app.mountDataQueue.put({
                'Name':
                'GetLocalTime',
                'Value':
                '{0}'.format(self.sidereal_time)
            })  # Sidereal local time
        reply = self.sendCommand('GR')
        if reply:
            self.raJnow = self.degStringToDecimal(reply)
        reply = self.sendCommand('GD')
        if reply:
            self.decJnow = self.degStringToDecimal(reply)
        reply = self.sendCommand(
            'Ginfo')  # use command "Ginfo" for fast topics
        if reply:  # if reply is there
            ra, dec, self.pierside, az, alt, self.jd, stat, slew = reply.rstrip(
                '#').strip().split(',')  # split the response to its parts
            # self.raJnow = float(ra)
            # self.decJnow = float(dec)
            self.jd = self.jd.rstrip('#')  # needed for 2.14.8 beta firmware
            self.az = float(az)  # same to azimuth
            self.alt = float(alt)  # and altitude
            self.stat = int(stat)  # status should be int for referencing list
            self.slewing = (slew == '1')  # set status slewing
            self.ra, self.dec = self.transformNovas(self.raJnow, self.decJnow,
                                                    2)  # convert J2000
            ra_show = self.decimalToDegree(self.ra, False, False)
            dec_show = self.decimalToDegree(self.dec, True, False)
            self.app.mountDataQueue.put({
                'Name': 'GetTelescopeDEC',
                'Value': '{0}'.format(dec_show)
            })  # put dec to gui
            self.app.mountDataQueue.put({
                'Name': 'GetTelescopeRA',
                'Value': '{0}'.format(ra_show)
            })  # put ra to gui
            self.app.mountDataQueue.put({
                'Name': 'GetTelescopeAltitude',
                'Value': '{0:03.2f}'.format(self.alt)
            })  # Altitude
            self.app.mountDataQueue.put({
                'Name': 'GetTelescopeAzimuth',
                'Value': '{0:03.2f}'.format(self.az)
            })  # Azimuth
            self.app.mountDataQueue.put({
                'Name': 'GetMountStatus',
                'Value': '{0}'.format(self.stat)
            })  # Mount status -> slew to stop
            if str(self.pierside) == str('W'):  # pier side
                self.app.mountDataQueue.put({
                    'Name': 'GetTelescopePierSide',
                    'Value': 'WEST'
                })  # Transfer to test in GUI
            else:  #
                self.app.mountDataQueue.put({
                    'Name': 'GetTelescopePierSide',
                    'Value': 'EAST'
                })  # Transfer to Text for GUI
            self.signalMountAzAltPointer.emit(
                self.az,
                self.alt)  # set azalt Pointer in diagrams to actual pos
            self.timeToFlip = self.sendCommand('Gmte')
            self.app.mountDataQueue.put({
                'Name': 'GetTimeToTrackingLimit',
                'Value': self.timeToFlip
            })  # Flip time
            # TODO:  precision of moutn jnow data # print(self.raJnow - float(ra), self.decJnow - float(dec))

    def getStatusMedium(self):  # medium status items like refraction
        if self.app.ui.checkAutoRefraction.isChecked(
        ):  # check if autorefraction is set
            if self.stat != 0:  # if no tracking, than autorefraction is good
                self.setRefractionParameter(
                )  # transfer refraction from to mount
            else:  #
                success, message = self.app.cpObject.SgGetDeviceStatus(
                    'Camera')  # getting the Camera status
                if success and message in [
                        'IDLE', 'DOWNLOADING'
                ]:  # if tracking, when camera is idle or downloading
                    self.setRefractionParameter(
                    )  # transfer refraction to mount
                else:  # otherwise
                    self.logger.debug(
                        'getStatusMedium-> no autorefraction: {0}'.format(
                            message))  # no autorefraction is possible
        self.signalMountTrackPreview.emit()

    def getStatusSlow(self):  # slow update item like temps
        self.timeToFlip = self.sendCommand('Gmte')
        self.app.mountDataQueue.put({
            'Name': 'GetTimeToTrackingLimit',
            'Value': self.timeToFlip
        })  # Flip time
        self.refractionTemp = self.sendCommand('GRTMP')
        self.app.mountDataQueue.put({
            'Name': 'GetRefractionTemperature',
            'Value': self.refractionTemp
        })  # refraction temp out of mount
        self.refractionPressure = self.sendCommand('GRPRS')
        self.app.mountDataQueue.put({
            'Name': 'GetRefractionPressure',
            'Value': self.refractionPressure
        })  # refraction pressure out of mount
        self.app.mountDataQueue.put({
            'Name': 'GetTelescopeTempDEC',
            'Value': self.sendCommand('GTMP1')
        })  # temp motor circuit of both axes
        self.app.mountDataQueue.put({
            'Name': 'GetSlewRate',
            'Value': self.sendCommand('GMs')
        })  # get actual slew rate
        self.app.mountDataQueue.put({
            'Name': 'GetRefractionStatus',
            'Value': self.sendCommand('GREF')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetUnattendedFlip',
            'Value': self.sendCommand('Guaf')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetDualAxisTracking',
            'Value': self.sendCommand('Gdat')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetCurrentHorizonLimitHigh',
            'Value': self.sendCommand('Gh')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetCurrentHorizonLimitLow',
            'Value': self.sendCommand('Go')
        })

    def getStatusOnce(self):  # one time updates for settings
        self.sendCommand('U2')  # Set high precision mode
        self.site_height = self.sendCommand('Gev')  # site height
        lon1 = self.sendCommand('Gg')  # get site lon
        if lon1[0] == '-':  # due to compatibility to LX200 protocol east is negative
            self.site_lon = lon1.replace('-', '+')  # change that
        else:
            self.site_lon = lon1.replace('+', '-')  # and vice versa
        self.site_lat = self.sendCommand('Gt')  # get site latitude
        self.transform.Refraction = False  # set parameter for ascom nova library
        self.transform.SiteElevation = float(self.site_height)  # height
        self.transform.SiteLatitude = self.degStringToDecimal(
            self.site_lat)  # site lat
        self.transform.SiteLongitude = self.degStringToDecimal(
            self.site_lon)  # site lon
        self.app.mountDataQueue.put({
            'Name': 'GetCurrentSiteElevation',
            'Value': self.site_height
        })  # write data to GUI
        self.app.mountDataQueue.put({
            'Name': 'GetCurrentSiteLongitude',
            'Value': lon1
        })
        self.app.mountDataQueue.put({
            'Name': 'GetCurrentSiteLatitude',
            'Value': self.site_lat
        })
        self.app.mountDataQueue.put({
            'Name': 'GetFirmwareDate',
            'Value': self.sendCommand('GVD')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetFirmwareNumber',
            'Value': self.sendCommand('GVN')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetFirmwareProductName',
            'Value': self.sendCommand('GVP')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetFirmwareTime',
            'Value': self.sendCommand('GVT')
        })
        self.app.mountDataQueue.put({
            'Name': 'GetHardwareVersion',
            'Value': self.sendCommand('GVZ')
        })
        self.logger.debug('getStatusOnce  -> FW:{0}'.format(
            self.sendCommand('GVN')))  # firmware version for checking
        self.logger.debug('getStatusOnce  -> Site Lon:{0}'.format(
            self.site_lon))  # site lon
        self.logger.debug('getStatusOnce  -> Site Lat:{0}'.format(
            self.site_lat))  # site lat
        self.logger.debug('getStatusOnce  -> Site Height:{0}'.format(
            self.site_height))  # site height

    def setupDriver(self):
        try:
            self.chooser = Dispatch('ASCOM.Utilities.Chooser')
            self.chooser.DeviceType = 'Telescope'
            self.driverName = self.chooser.Choose(self.driverName)
            self.logger.debug('setupDriverMoun-> driver chosen:{0}'.format(
                self.driverName))
            if self.driverName == 'ASCOM.FrejvallGM.Telescope':
                self.driver_real = True
            else:
                self.driver_real = False
            self.connected = False  # run the driver setup dialog
        except Exception as e:  # general exception
            self.app.messageQueue.put(
                'Driver Exception in setupMount')  # write to gui
            self.logger.error(
                'setupDriver Mount -> general exception:{0}'.format(
                    e))  # write to log
            self.connected = False  # set to disconnected
        finally:  # won't stop the program, continue
            return