コード例 #1
0
def from_metar_to_list_of_features(airport: str, timestamp: datetime, m: Metar.Metar) -> List:

    result = [
        airport,
        timestamp,
        m.code,

        m.mod,

        # m.station_id,

        m.wind_speed.value("mps") if m.wind_speed else None,
        m.wind_gust.value("mps") if m.wind_gust else None,


        m.wind_dir.value() if m.wind_dir else None,
        m.wind_dir_from.value() if m.wind_dir_from else None,
        m.wind_dir_to.value() if m.wind_dir_to else None,

        m.vis.value("m") if m.vis else None,

        m.max_vis.value("m") if m.max_vis else None,
        m.max_vis_dir.value() if m.max_vis_dir else None,

        m.runway[0][1].value("m") if m.runway else None,
        m.runway[0][2].value("m") if m.runway else None,


        m.temp.value("C") if m.temp else None,
        m.dewpt.value("C") if m.dewpt else None,
        m.press.value("HPA") if m.press else None,

        str(m.sky_conditions("; ")),

        # str(m.weather),
        str(m.present_weather()),
        # str(m.recent),

        # str(m.sky),
        # str(m.windshear),

        # str(m._trend),
        # str(m._trend_groups),
        # str(m._remarks),
        # str(m._unparsed_groups),
        # str(m._unparsed_remarks),

    ]
    return result
コード例 #2
0
ファイル: __init__.py プロジェクト: paulhoule/tentacruel
def internal_metar(metar_text: str) -> Dict[str, Any]:
    """
    Convert the output of the Metar parser into a dictionary which could be
    queried in a document database

    :param metar_text: N
    :return: a Dict with decoded METAR information
    """
    document = {}
    wxd = Metar(metar_text)
    document["station"] = wxd.station_id

    if wxd.type:
        document["type"] = wxd.type

    if wxd.time:
        document["time"] = wxd.time.isoformat()+'Z'

    if wxd.temp:
        document["temp"] = wxd.temp.value(units="F")

    if wxd.dewpt:
        document["dewpt"] = wxd.dewpt.value(units="F")

    if "temp" in document and "dewpt" in document:
        document["humidity"] = rel_humidity(document["temp"], document["dewpt"])

    if wxd.wind_speed:
        document["wind_speed"] = wxd.wind_speed.value(units="mph")

    if wxd.wind_dir:
        document["wind_dir"] = wxd.wind_dir.value()

    if wxd.vis:
        document["visibility"] = wxd.vis.value(units="sm")

    if wxd.press:
        document["pressure"] = wxd.press.value(units="mb")

    if wxd.sky:
        document["sky"] = wxd.sky_conditions()

    if wxd.press_sea_level:
        document["pressure"] = wxd.press_sea_level.value("mb")

    document["code"] = wxd.code

    return document
コード例 #3
0
class VoiceAtis(object):

    STATION_SUFFIXES = ['TWR', 'APP', 'GND', 'DEL', 'DEP']

    SPEECH_RATE = 150

    SLEEP_TIME = 3  # s

    RADIO_RANGE = 180  # nm

    OFFSETS = [
        (0x034E, 'H'),  # com1freq
        (0x3118, 'H'),  # com2freq
        (0x3122, 'b'),  # radioActive
        (0x0560, 'l'),  # ac Latitude
        (0x0568, 'l'),  # ac Longitude
    ]

    WHAZZUP_URL = 'http://api.ivao.aero/getdata/whazzup/whazzup.txt.gz'
    WHAZZUP_METAR_URL = 'http://wx.ivao.aero/metar.php'

    OUR_AIRPORTS_URL = 'http://ourairports.com/data/'

    COM1_FREQUENCY_DEBUG = 199.99

    # EDDS
    #     COM2_FREQUENCY_DEBUG = 126.12
    #     LAT_DEBUG = 48.687
    #     LON_DEBUG = 9.205

    # EDDM
    #     COM2_FREQUENCY_DEBUG = 123.12
    #     LAT_DEBUG = 48.353
    #     LON_DEBUG = 11.786

    # LIRF
    COM2_FREQUENCY_DEBUG = 121.85
    LAT_DEBUG = 41.8
    LON_DEBUG = 12.2

    # LIBR
    COM2_FREQUENCY_DEBUG = 121.85
    LAT_DEBUG = 41.8
    LON_DEBUG = 12.2

    WHAZZUP_TEXT_DEBUG = r'H:\My Documents\Sonstiges\voiceAtis\whazzup_1.txt'

    ## Setup the VoiceAtis object.
    # Inits logger.
    # Downloads airport data.
    def __init__(self, **optional):
        #TODO: Remove the debug code when tested properly.
        #TODO: Improve logged messages.
        #TODO: Create GUI.

        # Process optional arguments.
        self.debug = optional.get('Debug', debug)

        # Get file path.
        self.rootDir = os.path.dirname(
            os.path.dirname(os.path.abspath(__file__)))

        # Init logging.
        self.logger = VaLogger(os.path.join(self.rootDir, 'voiceAtis', 'logs'))

        # First log message.
        self.logger.info('voiceAtis started')

        # Read file with airport frequencies and coordinates.
        self.logger.info('Downloading airport data. This may take some time.')
        self.getAirportData()
        self.logger.info('Finished downloading airport data.')

        # Show debug Info
        #TODO: Remove for release.
        if self.debug:
            self.logger.info('Debug mode on.')
            self.logger.setLevel(ConsoleLevel='debug')

    ## Establishs pyuipc connection.
    # Return 'True' on success or if pyuipc not installed.
    # Return 'False' on fail.
    def connectPyuipc(self):
        try:
            self.pyuipcConnection = pyuipc.open(0)
            self.pyuipcOffsets = pyuipc.prepare_data(self.OFFSETS)
            self.logger.info('FSUIPC connection established.')
            return True
        except NameError:
            self.pyuipcConnection = None
            self.logger.warning(
                'Error using PYUIPC, running voiceAtis without it.')
            return True
        except:
            self.logger.warning(
                'FSUIPC: No simulator detected. Start you simulator first!')
            return False

    ## Runs an infinite loop.
    # i.E. for use without GUI.
    def runLoop(self):

        # Establish pyuipc connection
        result = False
        while not result:
            result = self.connectPyuipc()
            if not result:
                self.logger.info('Retrying in 20 seconds.')
                time.sleep(20)

        # Infinite loop.
        try:
            while True:
                timeSleep = self.loopRun()
                time.sleep(timeSleep)

        except KeyboardInterrupt:
            # Actions at Keyboard Interrupt.
            self.logger.info('Loop interrupted by user.')
            if pyuipcImported:
                self.pyuipc.close()

    ## One cyle of a loop.
    # Returns the requested sleep time.
    def loopRun(self):

        # Get sim data.
        self.getPyuipcData()

        # Get best suitable Airport.
        self.getAirport()

        # Handle if no airport found.
        if self.airport is None:
            self.logger.info(
                'No airport found, sleeping for {} seconds...'.format(
                    self.SLEEP_TIME))
            return self.SLEEP_TIME
        else:
            self.logger.info('Airport: {}.'.format(self.airport))

        # Get whazzup file
        if not self.debug:
            self.getWhazzupText()
        else:
            self.getWhazzupTextDebug()

        # Read whazzup text and get a station.
        self.parseWhazzupText()

        # Check if station online.
        if self.atisRaw is not None:
            self.logger.info('Station found, decoding Atis.')
        else:
            # Actions, if no station online.
            self.logger.info('No station online, using metar only.')
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                self.metar = Metar(self.getAirportMetar(), strict=False)

            self.parseVoiceMetar()

            # Parse atis voice with metar only.
            self.atisVoice = '{}, {}.'.format(
                self.airportInfos[self.airport][3], self.metarVoice)

            # Read the metar.
            self.readVoice()

            return self.SLEEP_TIME

        # Parse ATIS.
        # Information.
        self.getInfoIdentifier()
        self.parseVoiceInformation()

        # Metar.
        if not self.ivac2:
            self.parseMetar(self.atisRaw[2].strip())
        else:
            for ar in self.atisRaw:
                if ar.startswith('METAR'):
                    self.parseMetar(ar.replace('METAR ', '').strip())
                    break

        self.parseVoiceMetar()

        # Runways / TRL / TA
        self.parseRawRwy()
        self.parseVoiceRwy()

        # comment.
        self.parseVoiceComment()

        # Compose complete atis voice string.
        self.atisVoice = '{} {} {} {} Information {}, out.'.format(
            self.informationVoice, self.rwyVoice, self.commentVoice,
            self.metarVoice, self.informationIdentifier)

        # Read the string.
        self.readVoice()

        # After successful reading.
        return 0

    ## Downloads and reads the whazzup from IVAO
    def getWhazzupText(self):
        urllib.urlretrieve(self.WHAZZUP_URL, 'whazzup.txt.gz')
        with gzip.open('whazzup.txt.gz', 'rb') as f:
            self.whazzupText = f.read().decode('iso-8859-15')
        os.remove('whazzup.txt.gz')

    ## Reads a whazzup file on disk.
    # For debug purposes.
    def getWhazzupTextDebug(self):
        with open(self.WHAZZUP_TEXT_DEBUG) as whazzupFile:
            self.whazzupText = whazzupFile.read()
        pass

    ## Find a station of the airport and read the ATIS string.
    def parseWhazzupText(self):
        # Find an open station
        for st in self.STATION_SUFFIXES:
            matchObj = re.search('{}\w*?_{}'.format(self.airport, st),
                                 self.whazzupText)

            if matchObj is not None:
                break

        if matchObj is not None:
            # Extract ATIS.
            lineStart = matchObj.start()
            lineEnd = self.whazzupText.find('\n', matchObj.start())
            stationInfo = self.whazzupText[lineStart:lineEnd].split(':')
            self.ivac2 = bool(int(stationInfo[39][0]) - 1)
            self.atisTextRaw = stationInfo[35].encode('iso-8859-15')
            self.atisRaw = stationInfo[35].encode('iso-8859-15').split('^§')
        else:
            self.atisRaw = None

    def parseMetar(self, metarString):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.metar = Metar(metarString, strict=False)

    ## Parse runway and transition data.
    # Get active runways for arrival and departure.
    # Get transistion level and altitude.
    def parseRawRwy(self):
        self.rwyInformation = [None, None, None, None]
        if not self.ivac2:
            strSplit = self.atisRaw[3].split(' / ')

            for sp in strSplit:
                # ARR.
                if sp[0:3] == 'ARR':
                    self.rwyInformation[0] = []
                    arr = sp.replace('ARR RWY ', '').strip()
                    starts = []
                    for ma in re.finditer('\d{2}[RLC]?', arr):
                        starts.append(ma.start())
                    for st in range(len(starts)):
                        if st < len(starts) - 1:
                            rwy = arr[starts[st]:starts[st + 1]]
                        else:
                            rwy = arr[starts[st]:]
                        curRwy = [rwy[0:2], None, None, None]
                        if 'L' in rwy:
                            curRwy[1] = 'Left'
                        if 'C' in rwy:
                            curRwy[2] = 'Center'
                        if 'R' in rwy:
                            curRwy[3] = 'Right'
                        self.rwyInformation[0].append(curRwy)

                # DEP.
                elif sp[0:3] == 'DEP':
                    self.rwyInformation[1] = []
                    dep = sp.replace('DEP RWY ', '').strip()
                    starts = []
                    for ma in re.finditer('\d{2}[RLC]?', dep):
                        starts.append(ma.start())
                    for st in range(len(starts)):
                        if st < len(starts) - 1:
                            rwy = dep[starts[st]:starts[st + 1]]
                        else:
                            rwy = dep[starts[st]:]
                        curRwy = [rwy[0:2], None, None, None]
                        if 'L' in rwy:
                            curRwy[1] = 'Left'
                        if 'C' in rwy:
                            curRwy[2] = 'Center'
                        if 'R' in rwy:
                            curRwy[3] = 'Right'
                        self.rwyInformation[1].append(curRwy)

                # TRL/TA
                elif sp[0:3] == 'TRL':
                    self.rwyInformation[2] = sp.strip().replace('TRL FL', '')

                elif sp[0:2] == 'TA':
                    self.rwyInformation[3] = sp.strip().replace('TA ',
                                                                '').replace(
                                                                    'FT', '')
        # Ivac 2
        else:
            for ar in self.atisRaw:
                if ar.startswith('TA'):
                    trlTaSplit = ar.split(' / ')
                    self.rwyInformation[3] = trlTaSplit[0].replace('TA ', '')
                    self.rwyInformation[2] = trlTaSplit[1].replace('TRL', '')

                elif ar.startswith('ARR'):
                    curRwy = [ar[8:10], None, None, None]
                    if 'L' in ar[8:]:
                        curRwy[1] = 'Left'
                    if 'C' in ar[8:]:
                        curRwy[2] = 'Center'
                    if 'R' in ar[8:]:
                        curRwy[3] = 'Right'
                    if self.rwyInformation[0] is None:
                        self.rwyInformation[0] = [curRwy]
                    else:
                        self.rwyInformation[0].append(curRwy)

                elif ar.startswith('DEP'):
                    curRwy = [ar[8:10], None, None, None]
                    if 'L' in ar[8:]:
                        curRwy[1] = 'Left'
                    if 'C' in ar[8:]:
                        curRwy[2] = 'Center'
                    if 'R' in ar[8:]:
                        curRwy[3] = 'Right'
                    if self.rwyInformation[1] is None:
                        self.rwyInformation[1] = [curRwy]
                    else:
                        self.rwyInformation[1].append(curRwy)

    ## Generate a string of the metar for voice generation.
    def parseVoiceMetar(self):
        self.metarVoice = 'Met report'

        # Time
        hours = parseVoiceInt('{:02d}'.format(self.metar._hour))
        minutes = parseVoiceInt('{:02d}'.format(self.metar._min))
        self.metarVoice = '{} time {} {}'.format(self.metarVoice, hours,
                                                 minutes)

        # Wind
        if self.metar.wind_speed._value != 0:
            if self.metar.wind_dir is not None:
                self.metarVoice = '{}, wind {}, {}'.format(
                    self.metarVoice,
                    parseVoiceString(self.metar.wind_dir.string()),
                    parseVoiceString(self.metar.wind_speed.string()))
            else:
                self.metarVoice = '{}, wind variable, {}'.format(
                    self.metarVoice,
                    parseVoiceString(self.metar.wind_speed.string()))
        else:
            self.metarVoice = '{}, wind calm'.format(
                self.metarVoice, self.metar.wind_dir.string(),
                self.metar.wind_speed.string())

        if self.metar.wind_gust is not None:
            self.metarVoice = '{}, maximum {}'.format(
                self.metarVoice,
                parseVoiceString(self.metar.wind_gust.string()))

        if self.metar.wind_dir_from is not None:
            self.metarVoice = '{}, variable between {} and {}'.format(
                self.metarVoice,
                parseVoiceString(self.metar.wind_dir_from.string()),
                parseVoiceString(self.metar.wind_dir_to.string()))

        # Visibility.
        #TODO: implement directions
        self.metarVoice = '{}, visibility {}'.format(self.metarVoice,
                                                     self.metar.vis.string())

        # runway visual range
        rvr = self.metar.runway_visual_range().replace(';', ',')
        if rvr:
            rvrNew = ''
            lastEnd = 0
            rvrPattern = re.compile('[0123]\d[LCR]?(?=,)')
            for ma in rvrPattern.finditer(rvr):
                rwyRaw = rvr[ma.start():ma.end()]
                rwyStr = parseVoiceInt(rwyRaw[0:2])
                if len(rwyRaw) > 2:
                    if rwyRaw[2] == 'L':
                        rwyStr = '{} left'.format(rwyStr)
                    elif rwyRaw[2] == 'C':
                        rwyStr = '{} center'.format(rwyStr)
                    elif rwyRaw[2] == 'R':
                        rwyStr = '{} right'.format(rwyStr)
                rvrNew = '{}{}{}'.format(rvrNew, rvr[lastEnd:ma.start()],
                                         rwyStr)
                lastEnd = ma.end()

            rvrNew = '{}{}'.format(rvrNew, rvr[lastEnd:])

            self.metarVoice = '{}, visual range {}'.format(
                self.metarVoice, rvrNew)

        # weather phenomena
        if self.metar.weather:
            self.metarVoice = '{}, {}'.format(
                self.metarVoice,
                self.metar.present_weather().replace(';', ','))

        # clouds
        if self.metar.sky:
            self.metarVoice = '{}, {}'.format(
                self.metarVoice,
                self.metar.sky_conditions(',').replace(',', ', ').replace(
                    'a few', 'few'))
        elif 'CAVOK' in self.metar.code:
            self.metarVoice = '{}, clouds and visibility ok'.format(
                self.metarVoice)

        # runway condition
        #TODO: Implement runway conditions
        # Not implemented in python-metar

        # temperature
        tempValue = parseVoiceInt(str(int(self.metar.temp._value)))
        if self.metar.temp._units == 'C':
            tempUnit = 'degree Celsius'
        else:
            tempUnit = 'degree Fahrenheit'

        self.metarVoice = '{}, temperature {} {}'.format(
            self.metarVoice, tempValue, tempUnit)

        # dew point
        dewptValue = parseVoiceInt(str(int(self.metar.dewpt._value)))
        if self.metar.dewpt._units == 'C':
            dewptUnit = 'degree Celsius'
        else:
            dewptUnit = 'degree Fahrenheit'

        self.metarVoice = '{}, dew point {} {}'.format(self.metarVoice,
                                                       dewptValue, dewptUnit)

        # QNH
        if self.metar.press._units == 'MB':
            pressValue = parseVoiceInt(str(int(self.metar.press._value)))
            self.metarVoice = '{}, Q N H {} hectopascal'.format(
                self.metarVoice, pressValue)
        else:
            self.metarVoice = '{}, Altimeter {}'.format(
                self.metarVoice, parseVoiceString(self.metar.press.string()))

        #TODO: implement trend

        self.metarVoice = '{},'.format(self.metarVoice)

    ## Generate a string of the information identifier for voice generation.
    def parseVoiceInformation(self):
        if not self.ivac2:
            timeMatch = re.search(r'\d{4}z', self.atisRaw[1])
            startInd = timeMatch.start()
            endInd = timeMatch.end() - 1
            timeStr = parseVoiceInt(self.atisRaw[1][startInd:endInd])

            self.informationVoice = '{} {}.'.format(
                self.atisRaw[1][0:startInd - 1], timeStr)

        else:
            information = self.atisRaw[1].split(' ')
            airport = information[0]
            airport = self.airportInfos[airport][3]
            time = parseVoiceInt(information[4][0:4])

            self.informationVoice = '{} Information {} recorded at {}.'.format(
                airport, self.informationIdentifier, time)

    ## Generate a string of the runway information for voice generation.
    def parseVoiceRwy(self):
        self.rwyVoice = ''

        # ARR.
        if self.rwyInformation[0] is not None:
            self.rwyVoice = '{}Arrival runway '.format(self.rwyVoice)
            for arr in self.rwyInformation[0]:
                if arr[1:4].count(None) == 3:
                    self.rwyVoice = '{}{} and '.format(self.rwyVoice,
                                                       parseVoiceInt(arr[0]))
                else:
                    for si in arr[1:4]:
                        if si is not None:
                            self.rwyVoice = '{}{} {} and '.format(
                                self.rwyVoice, parseVoiceInt(arr[0]), si)
            self.rwyVoice = '{},'.format(self.rwyVoice[0:-5])

        # DEP.
        if self.rwyInformation[1] is not None:
            self.rwyVoice = '{} Departure runway '.format(self.rwyVoice)
            for dep in self.rwyInformation[1]:
                if dep[1:4].count(None) == 3:
                    self.rwyVoice = '{}{} and '.format(self.rwyVoice,
                                                       parseVoiceInt(dep[0]))
                else:
                    for si in dep[1:4]:
                        if si is not None:
                            self.rwyVoice = '{}{} {} and '.format(
                                self.rwyVoice, parseVoiceInt(dep[0]), si)
            self.rwyVoice = '{}, '.format(self.rwyVoice[0:-5])

        # TRL
        if self.rwyInformation[2] is not None:
            self.rwyVoice = '{}Transition level {}, '.format(
                self.rwyVoice, parseVoiceInt(self.rwyInformation[2]))

        # TA
        if self.rwyInformation[3] is not None:
            self.rwyVoice = '{}Transition altitude {} feet,'.format(
                self.rwyVoice, self.rwyInformation[3])

    ## Generate a string of ATIS comment for voice generation.
    def parseVoiceComment(self):
        if not self.ivac2:
            self.commentVoice = '{},'.format(parseVoiceString(self.atisRaw[4]))
        else:
            self.commentVoice = ''

    ## Reads the atis string using voice generation.
    def readVoice(self):
        # Init currently Reading with None.
        self.currentlyReading = None

        self.logger.debug('Voice Text is: {}'.format(self.atisVoice))

        if pyttsxImported:
            # Set properties currently reading
            self.currentlyReading = self.airport

            # Init voice engine.
            self.engine = pyttsx.init()

            # Set properties.
            voices = self.engine.getProperty('voices')
            for vo in voices:
                if 'english' in vo.name.lower():
                    self.engine.setProperty('voice', vo.id)
                    self.logger.debug('Using voice: {}'.format(vo.name))
                    break

            self.engine.setProperty('rate', self.SPEECH_RATE)

            # Start listener and loop.
            self.engine.connect('started-word', self.onWord)

            # Say complete ATIS
            self.engine.say(self.atisVoice)
            self.logger.info('Start reading.')
            self.engine.runAndWait()
            self.logger.info('Reading finished.')
            self.engine = None

        else:
            self.logger.warning(
                'Speech engine not initalized, no reading. Sleeping for {} seconds...'
                .format(self.SLEEP_TIME))
            time.sleep(self.SLEEP_TIME)

    ## Callback for stop of reading.
    # Stops reading if frequency change/com deactivation/out of range.
    def onWord(self, name, location, length):  # @UnusedVariable
        self.getPyuipcData()
        self.getAirport()

        if self.airport != self.currentlyReading:
            self.engine.stop()
            self.currentlyReading = None

    ## Reads current frequency and COM status.
    def getPyuipcData(self):

        if pyuipcImported:
            results = pyuipc.read(self.pyuipcOffsets)

            # frequency
            hexCode = hex(results[0])[2:]
            self.com1frequency = float('1{}.{}'.format(hexCode[0:2],
                                                       hexCode[2:]))
            hexCode = hex(results[1])[2:]
            self.com2frequency = float('1{}.{}'.format(hexCode[0:2],
                                                       hexCode[2:]))

            # radio active
            #TODO: Test accuracy of this data (with various planes and sims)
            radioActiveBits = list(map(int, '{0:08b}'.format(results[2])))
            if radioActiveBits[2]:
                self.com1active = True
                self.com2active = True
            elif radioActiveBits[0]:
                self.com1active = True
                self.com2active = False
            elif radioActiveBits[1]:
                self.com1active = False
                self.com2active = True
            else:
                self.com1active = False
                self.com2active = False

            # lat lon
            self.lat = results[3] * (90.0 / (10001750.0 * 65536.0 * 65536.0))
            self.lon = results[4] * (360.0 /
                                     (65536.0 * 65536.0 * 65536.0 * 65536.0))

        else:
            self.com1frequency = self.COM1_FREQUENCY_DEBUG
            self.com2frequency = self.COM2_FREQUENCY_DEBUG
            self.com1active = True
            self.com2active = True
            self.lat = self.LAT_DEBUG
            self.lon = self.LON_DEBUG

        # Logging.
        if self.com1active:
            com1activeStr = 'active'
        else:
            com1activeStr = 'inactive'
        if self.com2active:
            com2activeStr = 'active'
        else:
            com2activeStr = 'inactive'

        self.logger.debug('COM 1: {} ({}), COM 2: {} ({})'.format(
            self.com1frequency, com1activeStr, self.com2frequency,
            com2activeStr))


#         self.logger.debug('COM 1 active: {}, COM 2 active: {}'.format(self.com1active,self.com2active))

## Determine if there is an airport aplicable for ATIS reading.

    def getAirport(self):
        self.airport = None
        frequencies = []
        if self.com1active:
            frequencies.append(self.com1frequency)
        if self.com2active:
            frequencies.append(self.com2frequency)

        if frequencies:
            distanceMin = self.RADIO_RANGE + 1
            for ap in self.airportInfos:
                distance = gcDistanceNm(self.lat, self.lon,
                                        self.airportInfos[ap][1],
                                        self.airportInfos[ap][2])
                if (
                        floor(self.airportInfos[ap][0] * 100) / 100
                ) in frequencies and distance < self.RADIO_RANGE and distance < distanceMin:
                    distanceMin = distance
                    self.airport = ap

    ## Read data of airports from a given file.
    def getAirportDataFile(self, apFile):
        # Check if file exists.
        if not os.path.isfile(apFile):
            self.logger.warning('No such file: {}'.format(apFile))
            return

        # Read the file.
        with open(apFile) as aptInfoFile:
            for li in aptInfoFile:
                lineSplit = re.split('[,;]', li)
                if not li.startswith('#') and len(lineSplit) == 5:
                    self.airportInfos[lineSplit[0].strip()] = (float(
                        lineSplit[1]), float(lineSplit[2]), float(
                            lineSplit[3]), lineSplit[4].replace('\n', ''))

    ## Read data of airports from http://ourairports.com.
    def getAirportDataWeb(self):

        airportFreqs = {}

        # Read the file with frequency.
        with closing(
                urllib2.urlopen(self.OUR_AIRPORTS_URL +
                                'airport-frequencies.csv',
                                timeout=5)) as apFreqFile:
            for li in apFreqFile:
                lineSplit = li.split(',')
                if lineSplit[3] == '"ATIS"':
                    airportFreqs[lineSplit[2].replace('"', '')] = float(
                        lineSplit[-1].replace('\n', ''))

        # Read the file with other aiport data.
        # Add frequency and write them to self. airportInfos.
        with closing(urllib2.urlopen(self.OUR_AIRPORTS_URL +
                                     'airports.csv')) as apFile:
            for li in apFile:
                lineSplit = re.split((",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"), li)

                apCode = lineSplit[1].replace('"', '')
                if apCode in airportFreqs and len(apCode) <= 4:
                    apFreq = airportFreqs[apCode]
                    if 100.0 < apFreq < 140.0:
                        self.airportInfos[apCode] = [
                            apFreq,
                            float(lineSplit[4]),
                            float(lineSplit[5]), lineSplit[3].replace('"', '')
                        ]

    ## Reads airportData from two sources.
    def getAirportData(self):
        self.airportInfos = {}

        try:
            # Try to read airport data from web.
            self.getAirportDataWeb()
            self.getAirportDataFile(
                os.path.join(self.rootDir, 'airports_add.info'))
            collectedFromWeb = True

        except:
            # If this fails, use the airports from airports.info.
            self.logger.warning(
                'Unable to get airport data from web. Using airports.info. Error: {}'
                .format(sys.exc_info()[0]))
            self.airportInfos = {}
            collectedFromWeb = False
            try:
                self.getAirportDataFile(
                    os.path.join(self.rootDir, 'airports.info'))
            except:
                self.logger.error(
                    'Unable to read airport data from airports.info!')

        # Sort airportInfos and write them to a file for future use if collected from web.
        if collectedFromWeb:
            apInfoPath = os.path.join(self.rootDir, 'airports.info')
            apList = self.airportInfos.keys()
            apList.sort()
            with open(apInfoPath, 'w') as apDataFile:
                for ap in apList:
                    apDataFile.write(
                        '{:>4}; {:6.2f}; {:11.6f}; {:11.6f}; {}\n'.format(
                            ap, self.airportInfos[ap][0],
                            self.airportInfos[ap][1], self.airportInfos[ap][2],
                            self.airportInfos[ap][3]))

    ## Determines the info identifier of the loaded ATIS.
    def getInfoIdentifier(self):
        if not self.ivac2:
            informationPos = re.search('information ', self.atisRaw[1]).end()
            informationSplit = self.atisRaw[1][informationPos:].split(' ')
            self.informationIdentifier = informationSplit[0]
        else:
            self.informationIdentifier = CHAR_TABLE[re.findall(
                r'(?<=ATIS )[A-Z](?= \d{4})', self.atisRaw[1])[0]]

    ## Retrieves the metar of an airport independet of an ATIS.
    def getAirportMetar(self):

        if not debug:
            urllib.urlretrieve(self.WHAZZUP_METAR_URL, 'whazzup_metar.txt')

        with open('whazzup_metar.txt', 'r') as metarFile:
            metarText = metarFile.read()

        if not debug:
            os.remove('whazzup_metar.txt')

        metarStart = metarText.find(self.airport)
        metarEnd = metarText.find('\n', metarStart)

        return metarText[metarStart:metarEnd]
コード例 #4
0
  print "visibility: %s" % obs.visibility()

# The runway_visual_range() method summarizes the runway visibility
# observations.
if obs.runway:
  print "visual range: %s" % obs.runway_visual_range()

# The 'press' attribute is a pressure object.
if obs.press:
  print "pressure: %s" % obs.press.string("mb")

# The 'precip_1hr' attribute is a precipitation object.
if obs.precip_1hr:
  print "precipitation: %s" % obs.precip_1hr.string("in")

# The present_weather() method summarizes the weather description (rain, etc.)
print "weather: %s" % obs.present_weather()

# The sky_conditions() method summarizes the cloud-cover observations.
print "sky: %s" % obs.sky_conditions("\n     ")

# The remarks() method describes the remark groups that were parsed, but 
# are not available directly as Metar attributes.  The precipitation, 
# min/max temperature and peak wind remarks, for instance, are stored as
# attributes and won't be listed here.
if obs._remarks:
  print "remarks:"
  print "- "+obs.remarks("\n- ")

print "-----------------------------------------------------------------------\n"