コード例 #1
0
def parse_page(page):
    lines = filter(clean_line, page.split("\n"))
    records = map(get_date_and_standard_metar, lines)
    data = {
        "observation_time": [],
        "temperature": [],
        "dew_point": [],
        "pressure": [],
        "humidity": [],
    }

    for observation_time, raw_metar in records:
        try:
            m = Metar(raw_metar)
        except ParserError as err:
            logger.error(
                "Error parsing METAR: %s - %s",
                observation_time,
                raw_metar,
                exc_info=True,
            )
            continue
        temperature = m.temp.value()
        dew_point = m.dewpt.value()
        data["observation_time"].append(observation_time)
        data["temperature"].append(temperature)
        data["dew_point"].append(dew_point)
        data["pressure"].append(m.press.value())
        data["humidity"].append(humidity(temperature, dew_point))

    return pd.DataFrame.from_dict(data)
コード例 #2
0
def main():
    """Go Main Go"""
    pgconn = get_dbconn("asos")
    icursor = pgconn.cursor()
    icursor.execute("SET TIME ZONE 'UTC'")
    icursor2 = pgconn.cursor()

    sts = datetime.datetime(2011, 1, 1)
    ets = datetime.datetime(2012, 1, 1)
    interval = datetime.timedelta(days=1)
    now = sts
    while now < ets:
        icursor.execute("""
      select valid, station, metar from t%s
      where metar is not null and valid >= '%s' and valid < '%s'
        """ % (now.year, now.strftime("%Y-%m-%d"),
               (now+interval).strftime("%Y-%m-%d")))
        total = 0
        for row in icursor:
            try:
                mtr = Metar(row[2], row[0].month, row[0].year)
            except Exception as _exp:
                continue
            sql = 'update t%s SET ' % (now.year,)
            if mtr.max_temp_6hr:
                sql += "max_tmpf_6hr = %s," % (mtr.max_temp_6hr.value("F"),)
            if mtr.min_temp_6hr:
                sql += "min_tmpf_6hr = %s," % (mtr.min_temp_6hr.value("F"),)
            if mtr.max_temp_24hr:
                sql += "max_tmpf_24hr = %s," % (mtr.max_temp_24hr.value("F"),)
            if mtr.min_temp_24hr:
                sql += "min_tmpf_24hr = %s," % (mtr.min_temp_24hr.value("F"),)
            if mtr.precip_3hr:
                sql += "p03i = %s," % (mtr.precip_3hr.value("IN"),)
            if mtr.precip_6hr:
                sql += "p06i = %s," % (mtr.precip_6hr.value("IN"),)
            if mtr.precip_24hr:
                sql += "p24i = %s," % (mtr.precip_24hr.value("IN"),)
            if mtr.press_sea_level:
                sql += "mslp = %s," % (mtr.press_sea_level.value("MB"),)
            if mtr.weather:
                pwx = []
                for x in mtr.weather:
                    pwx.append(("").join([a for a in x if a is not None]))
                sql += "presentwx = '%s'," % ((",".join(pwx))[:24], )
            if sql == "update t%s SET " % (now.year,):
                continue
            sql = "%s WHERE station = '%s' and valid = '%s'" % (sql[:-1],
                                                                row[1],
                                                                row[0])
            # print sql
            icursor2.execute(sql)
            total += 1
            if total % 1000 == 0:
                print('Done total: %s now: %s' % (total, now))
                pgconn.commit()
        now += interval
    icursor2.close()
    pgconn.commit()
    pgconn.close()
コード例 #3
0
def parse_page(page):
    lines = filter(clean_line, page.split('\n'))
    records = map(get_date_and_standard_metar, lines)
    data = {
        'observation_time': [],
        'temperature': [],
        'dew_point': [],
        'pressure': [],
        'humidity': [],
    }

    for observation_time, raw_metar in records:
        try:
            m = Metar(raw_metar)
        except ParserError as err:
            logger.error(
                'Error parsing METAR: %s - %s',
                observation_time,
                raw_metar,
                exc_info=True,
            )
            continue
        temperature = m.temp.value()
        dew_point = m.dewpt.value()
        data['observation_time'].append(observation_time)
        data['temperature'].append(temperature)
        data['dew_point'].append(dew_point)
        data['pressure'].append(m.press.value())
        data['humidity'].append(humidity(temperature, dew_point))

    return pd.DataFrame.from_dict(data)
コード例 #4
0
ファイル: reprocess.py プロジェクト: josempolm/iem
def process_metar(mstr, now):
    """ Do the METAR Processing """
    mtr = None
    while mtr is None:
        try:
            mtr = Metar(mstr, now.month, now.year)
        except MetarParserError as exp:
            try:
                msg = str(exp)
            except Exception as exp:
                return None
            if msg.find("day is out of range for month") > 0 and now.day == 1:
                now -= datetime.timedelta(days=1)
                continue
            tokens = ERROR_RE.findall(str(exp))
            orig_mstr = mstr
            if tokens:
                for token in tokens[0].split():
                    mstr = mstr.replace(" %s" % (token, ), "")
                if orig_mstr == mstr:
                    print("Can't fix badly formatted metar: " + mstr)
                    return None
            else:
                print("MetarParserError: "+msg)
                print("    --> now: %s month: %s, year: %s" % (now, now.month,
                                                               now.year))
                sys.exit()
                return None
        except Exception, exp:
            print("Double Fail: %s %s" % (mstr, exp))
            return None
コード例 #5
0
def process_metar(mstr, now):
    """ Do the METAR Processing """
    mtr = None
    while mtr is None:
        try:
            mtr = Metar(mstr, now.month, now.year)
        except MetarParserError as exp:
            try:
                msg = str(exp)
            except Exception as exp:
                return None
            tokens = ERROR_RE.findall(str(exp))
            orig_mstr = mstr
            if tokens:
                for token in tokens[0].split():
                    mstr = mstr.replace(" %s" % (token, ), "")
                if orig_mstr == mstr:
                    print("Can't fix badly formatted metar: " + mstr)
                    return None
            else:
                print("MetarParserError: " + msg)
                return None
        except Exception, exp:
            print("Double Fail: %s %s" % (mstr, exp))
            return None
コード例 #6
0
ファイル: test_metar.py プロジェクト: walterroach/emiz
def test_set_weather_from_metar(metar, out, weather_test_file, out_file):
    in_metar = Metar(metar)
    with Miz(weather_test_file) as miz:
        _randomize_weather(miz.mission)
        miz.zip(out_file)
    emiz.weather.mizfile.set_weather_from_metar(metar, out_file, out_file)
    out_metar = Metar(
        emiz.weather.mizfile.get_metar_from_mission(out_file, 'UGTB'))
    assert in_metar.temp.value() == out_metar.temp.value()
    assert int(
        in_metar.wind_speed.value('MPS')) == out_metar.wind_speed.value('MPS')
    assert in_metar.wind_dir.value() == out_metar.wind_dir.value()
    with Miz(out_file) as miz:
        assert miz.mission.weather.wind_at_ground_level_dir == emiz.weather.utils.reverse_direction(
            in_metar.wind_dir.value())
        assert miz.mission.weather.wind_at2000_speed >= miz.mission.weather.wind_at_ground_level_speed
        assert miz.mission.weather.wind_at8000_speed >= miz.mission.weather.wind_at_ground_level_speed
        for key in out:
            if isinstance(out[key], tuple):
                assert out[key][0] <= getattr(miz.mission.weather,
                                              key) <= out[key][1]
            else:
                assert getattr(miz.mission.weather, key) == out[key], key
コード例 #7
0
def weather_today_job():
    # request data from NOAA server (METAR of Nancy-Essey Airport)
    r = requests.get(
        'http://tgftp.nws.noaa.gov/data/observations/metar/stations/LFSN.TXT',
        timeout=10.0,
        headers={'User-Agent': USER_AGENT})
    # check error
    if r.status_code == 200:
        # extract METAR message
        metar_msg = r.content.decode().split('\n')[1]
        # METAR parse
        obs = Metar(metar_msg)
        # init and populate d_today dict
        d_today = {}
        # message date and time
        if obs.time:
            d_today['update_iso'] = obs.time.strftime('%Y-%m-%dT%H:%M:%SZ')
            d_today['update_fr'] = dt_utc_to_local(
                obs.time).strftime('%H:%M %d/%m')
        # current temperature
        if obs.temp:
            d_today['temp'] = round(obs.temp.value('C'))
        # current dew point
        if obs.dewpt:
            d_today['dewpt'] = round(obs.dewpt.value('C'))
        # current pressure
        if obs.press:
            d_today['press'] = round(obs.press.value('hpa'))
        # current wind speed
        if obs.wind_speed:
            d_today['w_speed'] = round(obs.wind_speed.value('KMH'))
        # current wind gust
        if obs.wind_gust:
            d_today['w_gust'] = round(obs.wind_gust.value('KMH'))
        # current wind direction
        if obs.wind_dir:
            # replace 'W'est by 'O'uest
            d_today['w_dir'] = obs.wind_dir.compass().replace('W', 'O')
        # weather status str
        d_today['descr'] = 'n/a'
        # store to redis
        DB.main.set_as_json('json:weather:today:nancy', d_today, ex=2 * 3600)
コード例 #8
0
def add_ground_wind(airport_code, aloft_wind):
    """
	Add the wind information at the ground for the given station code.
	"""
    raw = requests.get(BASE_ADDR.format(airport_code.upper()))
    if raw.status_code == 404:
        raw = requests.get(BASE_ADDR.format('K' + airport_code.upper()))

    if raw.status_code == 404:
        raise ValueError('The given station code is invalid.')

    ground_wind = {'altitude': 0, 'direction': 0, 'speed': 0}

    for line in raw.text.split('\n'):
        if airport_code.upper() in line:
            line = line.strip()
            observation = Metar(line)
            ground_wind['direction'] = observation.wind_dir.value()
            ground_wind['speed'] = observation.wind_speed.value(units='KT')

    return [ground_wind] + aloft_wind
コード例 #9
0
def process_metar(mstr, now):
    """ Do the METAR Processing """
    mtr = None
    while mtr is None:
        try:
            mtr = Metar(mstr, now.month, now.year)
        except MetarParserError as exp:
            try:
                msg = str(exp)
            except Exception as exp:
                return None
            if msg.find("day is out of range for month") > 0 and now.day == 1:
                now -= datetime.timedelta(days=1)
                continue
            tokens = ERROR_RE.findall(str(exp))
            orig_mstr = mstr
            if tokens:
                for token in tokens[0].split():
                    mstr = mstr.replace(" %s" % (token, ), "")
                if orig_mstr == mstr:
                    print("Can't fix badly formatted metar: " + mstr)
                    return None
            else:
                print("MetarParserError: " + msg)
                print("    --> now: %s month: %s, year: %s" %
                      (now, now.month, now.year))
                sys.exit()
                return None
        except Exception as exp:
            print("Double Fail: %s %s" % (mstr, exp))
            return None
    if mtr is None or mtr.time is None:
        return None

    ob = OB()
    ob.metar = mstr[:254]

    gts = datetime.datetime(
        mtr.time.year,
        mtr.time.month,
        mtr.time.day,
        mtr.time.hour,
        mtr.time.minute,
    )
    gts = gts.replace(tzinfo=pytz.UTC)
    # When processing data on the last day of the month, we get GMT times
    # for the first of this month
    if gts.day == 1 and now.day > 10:
        tm = now + datetime.timedelta(days=1)
        gts = gts.replace(year=tm.year, month=tm.month, day=tm.day)

    ob.valid = gts

    if mtr.temp:
        ob.tmpf = mtr.temp.value("F")
    if mtr.dewpt:
        ob.dwpf = mtr.dewpt.value("F")

    if mtr.wind_speed:
        ob.sknt = mtr.wind_speed.value("KT")
    if mtr.wind_gust:
        ob.gust = mtr.wind_gust.value("KT")

    if mtr.wind_dir and mtr.wind_dir.value() != "VRB":
        ob.drct = mtr.wind_dir.value()

    if mtr.vis:
        ob.vsby = mtr.vis.value("SM")

    if mtr.press:
        ob.alti = mtr.press.value("IN")

    if mtr.press_sea_level:
        ob.mslp = mtr.press_sea_level.value("MB")

    if mtr.precip_1hr:
        ob.p01i = mtr.precip_1hr.value("IN")

    # Do something with sky coverage
    for i in range(len(mtr.sky)):
        (c, h, _) = mtr.sky[i]
        setattr(ob, "skyc%s" % (i + 1), c)
        if h is not None:
            setattr(ob, "skyl%s" % (i + 1), h.value("FT"))

    if mtr.max_temp_6hr:
        ob.max_tmpf_6hr = mtr.max_temp_6hr.value("F")
    if mtr.min_temp_6hr:
        ob.min_tmpf_6hr = mtr.min_temp_6hr.value("F")
    if mtr.max_temp_24hr:
        ob.max_tmpf_24hr = mtr.max_temp_24hr.value("F")
    if mtr.min_temp_24hr:
        ob.min_tmpf_6hr = mtr.min_temp_24hr.value("F")
    if mtr.precip_3hr:
        ob.p03i = mtr.precip_3hr.value("IN")
    if mtr.precip_6hr:
        ob.p06i = mtr.precip_6hr.value("IN")
    if mtr.precip_24hr:
        ob.p24i = mtr.precip_24hr.value("IN")

    # Presentwx
    if mtr.weather:
        pwx = []
        for x in mtr.weather:
            pwx.append(("").join([a for a in x if a is not None]))
        ob.wxcodes = pwx

    return ob
コード例 #10
0
    def process_data(self):
        try:
            self.log.info('Processing Metar data...')

            with open(os.path.join(os.path.dirname(__file__), 'metar/stations.json')) as in_file:
                icao = json.load(in_file)

            now = arrow.utcnow()
            hour = now.hour
            minute = now.minute

            if minute < 45:
                current_cycle = hour
            else:
                current_cycle = hour + 1 % 24

            stations = {}
            for cycle in (current_cycle-1, current_cycle):
                file = f'http://tgftp.nws.noaa.gov/data/observations/metar/cycles/{cycle:02d}Z.TXT'
                self.log.info(f"Processing '{file}' ...")

                request = requests.get(file, stream=True, timeout=(self.connect_timeout, self.read_timeout))
                for line in request.iter_lines():
                    if line:
                        data = line.decode('iso-8859-1')
                        try:
                            # Is this line a date with format "2017/05/12 23:55" ?
                            arrow.get(data, 'YYYY/MM/DD HH:mm')
                            continue
                            # Catch also ValueError because https://github.com/crsmithdev/arrow/issues/535
                        except (arrow.parser.ParserError, ValueError):
                            try:
                                metar = Metar(data, strict=False)
                                # wind_dir could be NONE if 'dir' is 'VRB'
                                if metar.wind_speed:
                                    if metar.station_id not in stations:
                                        stations[metar.station_id] = {}
                                    key = arrow.get(metar.time).timestamp
                                    stations[metar.station_id][key] = metar
                            except Exception as e:
                                self.log.warn(f'Error while parsing METAR data: {e}')
                                continue

            for metar_id in stations:
                metar = next(iter(stations[metar_id].values()))
                try:
                    name, short_name, default_name, lat, lon, altitude, tz = None, None, None, None, None, None, None

                    checkwx_key = f'metar/checkwx/{metar.station_id}'
                    if not self.redis.exists(checkwx_key):
                        try:
                            self.log.info('Calling api.checkwx.com...')
                            request = requests.get(
                                f'https://api.checkwx.com/station/{metar.station_id}',
                                headers={'Accept': 'application/json', 'X-API-Key': self.checkwx_api_key},
                                timeout=(self.connect_timeout, self.read_timeout)
                            )
                            if request.status_code == 401:
                                raise UsageLimitException(request.json()['errors'][0]['message'])
                            elif request.status_code == 429:
                                raise UsageLimitException('api.checkwx.com rate limit exceeded')

                            try:
                                checkwx_data = request.json()['data'][0]
                                if 'icao' not in checkwx_data:
                                    raise ProviderException('Invalid CheckWX data')
                            except (ValueError, KeyError):
                                checkwx_json = request.json()
                                messages = []
                                if type(checkwx_json['data']) is list:
                                    messages.extend(checkwx_json['data'])
                                else:
                                    messages.append(checkwx_json['data'])
                                raise ProviderException(f'CheckWX API error: {",".join(messages)}')

                            self.add_redis_key(checkwx_key, {
                                'data': json.dumps(checkwx_data),
                                'date': arrow.now().format('YYYY-MM-DD HH:mm:ssZZ'),
                            }, self.checkwx_cache_duration)
                        except TimeoutError as e:
                            raise e
                        except UsageLimitException as e:
                            self.add_redis_key(checkwx_key, {
                                'error': repr(e),
                                'date': arrow.now().format('YYYY-MM-DD HH:mm:ssZZ'),
                            }, self.usage_limit_cache_duration)
                        except Exception as e:
                            if not isinstance(e, ProviderException):
                                self.log.exception('Error while getting CheckWX data')
                            else:
                                self.log.warn(f'Error while getting CheckWX data: {e}')
                            self.add_redis_key(checkwx_key, {
                                'error': repr(e),
                                'date': arrow.now().format('YYYY-MM-DD HH:mm:ssZZ'),
                            }, self.checkwx_cache_duration)

                    if not self.redis.hexists(checkwx_key, 'error'):
                        checkwx_data = json.loads(self.redis.hget(checkwx_key, 'data'))

                        station_type = checkwx_data.get('type', None)
                        if station_type:
                            name = f'{checkwx_data["name"]} {station_type}'
                        else:
                            name = checkwx_data['name']
                        city = checkwx_data.get('city', None)
                        if city:
                            if station_type:
                                short_name = f'{city} {station_type}'
                            else:
                                short_name = city
                        else:
                            default_name = checkwx_data['name']

                        lat = checkwx_data['latitude']['decimal']
                        lon = checkwx_data['longitude']['decimal']
                        tz = checkwx_data['timezone']['tzid']
                        elevation = checkwx_data.get('elevation', None)
                        altitude = None
                        if elevation:
                            if 'meters' in elevation:
                                altitude = Q_(elevation['meters'], ureg.meters)
                            elif 'feet' in elevation:
                                altitude = Q_(elevation['feet'], ureg.feet)

                    if metar.station_id in icao:
                        lat = lat or icao[metar.station_id]['lat']
                        lon = lon or icao[metar.station_id]['lon']
                        default_name = default_name or icao[metar.station_id]['name']

                    station = self.save_station(
                        metar.station_id,
                        short_name,
                        name,
                        lat,
                        lon,
                        Status.GREEN,
                        altitude=altitude,
                        tz=tz,
                        url=os.path.join(self.provider_url, f'site?id={metar.station_id}&db=metar'),
                        default_name=default_name or f'{metar.station_id} Airport',
                        lookup_name=f'{metar.station_id} Airport ICAO')
                    station_id = station['_id']

                    if metar.station_id not in icao:
                        self.log.warn(f"Missing '{metar.station_id}' ICAO in database. Is it '{station['name']}'?")

                    measures_collection = self.measures_collection(station_id)
                    new_measures = []
                    for key in stations[metar_id]:
                        metar = stations[metar_id][key]
                        if not self.has_measure(measures_collection, key):
                            temp = self.get_quantity(metar.temp, self.temperature_units)
                            dew_point = self.get_quantity(metar.dewpt, self.temperature_units)
                            humidity = self.compute_humidity(dew_point, temp)
                            measure = self.create_measure(
                                station,
                                key,
                                self.get_direction(metar.wind_dir),
                                self.get_quantity(metar.wind_speed, self.speed_units),
                                self.get_quantity(metar.wind_gust or metar.wind_speed, self.speed_units),
                                temperature=temp,
                                humidity=humidity,
                                pressure=Pressure(qfe=None,
                                                  qnh=self.get_quantity(metar.press, self.pressure_units),
                                                  qff=self.get_quantity(metar.press_sea_level, self.pressure_units))
                            )
                            new_measures.append(measure)

                    self.insert_new_measures(measures_collection, station, new_measures)

                except ProviderException as e:
                    self.log.warn(f"Error while processing station '{metar_id}': {e}")
                except Exception as e:
                    self.log.exception(f"Error while processing station '{metar_id}': {e}")

        except Exception as e:
            self.log.exception(f'Error while processing Metar: {e}')

        self.log.info('Done !')
コード例 #11
0
ファイル: ds3505.py プロジェクト: morganetanu/pyIEM
def process_metar(mstr, now):
    """ Do the METAR Processing """
    mtr = None
    while mtr is None:
        try:
            mtr = Metar(mstr, now.month, now.year)
        except MetarParserError as exp:
            try:
                msg = str(exp)
            except Exception as exp:
                return None
            tokens = ERROR_RE.findall(str(exp))
            orig_mstr = mstr
            if tokens:
                for token in tokens[0].split():
                    mstr = mstr.replace(" %s" % (token, ), "")
                if orig_mstr == mstr:
                    print("Can't fix badly formatted metar: " + mstr)
                    return None
            else:
                print("MetarParserError: "+msg)
                return None
        except Exception as exp:
            print("Double Fail: %s %s" % (mstr, exp))
            return None
    if mtr is None or mtr.time is None:
        return None

    ob = OB()
    ob.metar = mstr[:254]
    ob.valid = now

    if mtr.temp:
        ob.tmpf = mtr.temp.value("F")
    if mtr.dewpt:
        ob.dwpf = mtr.dewpt.value("F")

    if mtr.wind_speed:
        ob.sknt = mtr.wind_speed.value("KT")
    if mtr.wind_gust:
        ob.gust = mtr.wind_gust.value("KT")

    if mtr.wind_dir and mtr.wind_dir.value() != "VRB":
        ob.drct = mtr.wind_dir.value()

    if mtr.vis:
        ob.vsby = mtr.vis.value("SM")

    # see pull request #38
    if mtr.press and mtr.press != mtr.press_sea_level:
        ob.alti = mtr.press.value("IN")

    if mtr.press_sea_level:
        ob.mslp = mtr.press_sea_level.value("MB")

    if mtr.precip_1hr:
        ob.p01i = mtr.precip_1hr.value("IN")

    # Do something with sky coverage
    for i in range(len(mtr.sky)):
        (c, h, _) = mtr.sky[i]
        setattr(ob, 'skyc%s' % (i+1), c)
        if h is not None:
            setattr(ob, 'skyl%s' % (i+1), h.value("FT"))

    if mtr.max_temp_6hr:
        ob.max_tmpf_6hr = mtr.max_temp_6hr.value("F")
    if mtr.min_temp_6hr:
        ob.min_tmpf_6hr = mtr.min_temp_6hr.value("F")
    if mtr.max_temp_24hr:
        ob.max_tmpf_24hr = mtr.max_temp_24hr.value("F")
    if mtr.min_temp_24hr:
        ob.min_tmpf_6hr = mtr.min_temp_24hr.value("F")
    if mtr.precip_3hr:
        ob.p03i = mtr.precip_3hr.value("IN")
    if mtr.precip_6hr:
        ob.p06i = mtr.precip_6hr.value("IN")
    if mtr.precip_24hr:
        ob.p24i = mtr.precip_24hr.value("IN")

    # Presentwx
    if mtr.weather:
        pwx = []
        for x in mtr.weather:
            pwx.append(("").join([a for a in x if a is not None]))
        ob.presentwx = (",".join(pwx))[:24]

    return ob
コード例 #12
0
def process_metar(mstr, now):
    """ Do the METAR Processing """
    mtr = None
    while mtr is None:
        try:
            mtr = Metar(mstr, now.month, now.year)
        except MetarParserError as exp:
            try:
                msg = str(exp)
            except Exception as exp:
                return None
            tokens = ERROR_RE.findall(str(exp))
            orig_mstr = mstr
            if tokens:
                for token in tokens[0].split():
                    mstr = mstr.replace(" %s" % (token, ), "")
                if orig_mstr == mstr:
                    print("Can't fix badly formatted metar: " + mstr)
                    return None
            else:
                print("MetarParserError: " + msg)
                return None
        except Exception as exp:
            print("Double Fail: %s %s" % (mstr, exp))
            return None
    if mtr is None or mtr.time is None:
        return None

    ob = OB()
    ob.metar = mstr[:254]
    ob.valid = now

    if mtr.temp:
        ob.tmpf = mtr.temp.value("F")
    if mtr.dewpt:
        ob.dwpf = mtr.dewpt.value("F")

    if mtr.wind_speed:
        ob.sknt = mtr.wind_speed.value("KT")
    if mtr.wind_gust:
        ob.gust = mtr.wind_gust.value("KT")

    # Calc some stuff
    if ob.tmpf is not None and ob.dwpf is not None:
        ob.relh = relative_humidity_from_dewpoint(
            ob.tmpf * units('degF'),
            ob.dwpf * units('degF')).to(units('percent')).magnitude
        if ob.sknt is not None:
            ob.feel = apparent_temperature(ob.tmpf * units('degF'),
                                           ob.relh * units('percent'),
                                           ob.sknt * units('knots')).to(
                                               units('degF')).magnitude

    if mtr.wind_dir and mtr.wind_dir.value() != "VRB":
        ob.drct = mtr.wind_dir.value()

    if mtr.vis:
        ob.vsby = mtr.vis.value("SM")

    # see pull request #38
    if mtr.press and mtr.press != mtr.press_sea_level:
        ob.alti = mtr.press.value("IN")

    if mtr.press_sea_level:
        ob.mslp = mtr.press_sea_level.value("MB")

    if mtr.precip_1hr:
        ob.p01i = mtr.precip_1hr.value("IN")

    # Do something with sky coverage
    for i in range(len(mtr.sky)):
        (c, h, _) = mtr.sky[i]
        setattr(ob, 'skyc%s' % (i + 1), c)
        if h is not None:
            setattr(ob, 'skyl%s' % (i + 1), h.value("FT"))

    if mtr.max_temp_6hr:
        ob.max_tmpf_6hr = mtr.max_temp_6hr.value("F")
    if mtr.min_temp_6hr:
        ob.min_tmpf_6hr = mtr.min_temp_6hr.value("F")
    if mtr.max_temp_24hr:
        ob.max_tmpf_24hr = mtr.max_temp_24hr.value("F")
    if mtr.min_temp_24hr:
        ob.min_tmpf_6hr = mtr.min_temp_24hr.value("F")
    if mtr.precip_3hr:
        ob.p03i = mtr.precip_3hr.value("IN")
    if mtr.precip_6hr:
        ob.p06i = mtr.precip_6hr.value("IN")
    if mtr.precip_24hr:
        ob.p24i = mtr.precip_24hr.value("IN")

    # Presentwx
    if mtr.weather:
        pwx = []
        for wx in mtr.weather:
            val = "".join([a for a in wx if a is not None])
            if val == "" or val == len(val) * "/":
                continue
            pwx.append(val)
        ob.wxcodes = pwx

    return ob
コード例 #13
0
 def parseMetar(self, metarString):
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
         self.metar = Metar(metarString, strict=False)
コード例 #14
0
    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
コード例 #15
0
    def process_data(self):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            try:
                self.log.info("Processing Metar data...")

                with open(
                        os.path.join(os.path.dirname(__file__),
                                     "../metar/stations.json")) as in_file:
                    icao = json.load(in_file)

                now = arrow.utcnow()
                hour = now.hour
                minute = now.minute

                if minute < 45:
                    current_cycle = hour
                else:
                    current_cycle = hour + 1 % 24

                stations = {}
                for cycle in (current_cycle - 1, current_cycle):
                    file = f"http://tgftp.nws.noaa.gov/data/observations/metar/cycles/{cycle:02d}Z.TXT"
                    self.log.info(f"Processing '{file}' ...")

                    request = requests.get(file,
                                           stream=True,
                                           timeout=(self.connect_timeout,
                                                    self.read_timeout))
                    for line in request.iter_lines():
                        if line:
                            data = line.decode("iso-8859-1")
                            try:
                                # Is this line a date with format "2017/05/12 23:55" ?
                                arrow.get(data, "YYYY/MM/DD HH:mm")
                                continue
                                # Catch also ValueError because https://github.com/crsmithdev/arrow/issues/535
                            except (arrow.parser.ParserError, ValueError):
                                try:
                                    metar = Metar(data, strict=False)
                                    # wind_dir could be NONE if 'dir' is 'VRB'
                                    if metar.wind_speed:
                                        if metar.station_id not in stations:
                                            stations[metar.station_id] = {}
                                        key = arrow.get(
                                            metar.time).int_timestamp
                                        stations[metar.station_id][key] = metar
                                except Exception as e:
                                    self.log.warning(
                                        f"Error while parsing METAR data: {e}")
                                    continue

                for metar_id in stations:
                    metar = next(iter(stations[metar_id].values()))
                    try:
                        name, short_name, default_name, lat, lon, altitude, tz = (
                            None,
                            None,
                            None,
                            None,
                            None,
                            None,
                            None,
                        )

                        checkwx_key = f"metar/checkwx/{metar.station_id}"
                        if not self.redis.exists(checkwx_key):
                            try:
                                self.log.info("Calling api.checkwx.com...")
                                request = requests.get(
                                    f"https://api.checkwx.com/station/{metar.station_id}",
                                    headers={
                                        "Accept": "application/json",
                                        "X-API-Key": self.checkwx_api_key
                                    },
                                    timeout=(self.connect_timeout,
                                             self.read_timeout),
                                )
                                if request.status_code == 401:
                                    raise UsageLimitException(
                                        request.json()["errors"][0]["message"])
                                elif request.status_code == 429:
                                    raise UsageLimitException(
                                        "api.checkwx.com rate limit exceeded")

                                try:
                                    checkwx_data = request.json()["data"][0]
                                    if "icao" not in checkwx_data:
                                        raise ProviderException(
                                            "Invalid CheckWX data")
                                except (ValueError, KeyError):
                                    checkwx_json = request.json()
                                    messages = []
                                    if type(checkwx_json["data"]) is list:
                                        messages.extend(checkwx_json["data"])
                                    else:
                                        messages.append(checkwx_json["data"])
                                    raise ProviderException(
                                        f'CheckWX API error: {",".join(messages)}'
                                    )

                                self.add_redis_key(
                                    checkwx_key,
                                    {
                                        "data":
                                        json.dumps(checkwx_data),
                                        "date":
                                        arrow.now().format(
                                            "YYYY-MM-DD HH:mm:ssZZ"),
                                    },
                                    self.checkwx_cache_duration,
                                )
                            except TimeoutError as e:
                                raise e
                            except UsageLimitException as e:
                                self.add_redis_key(
                                    checkwx_key,
                                    {
                                        "error":
                                        repr(e),
                                        "date":
                                        arrow.now().format(
                                            "YYYY-MM-DD HH:mm:ssZZ"),
                                    },
                                    self.usage_limit_cache_duration,
                                )
                            except Exception as e:
                                if not isinstance(e, ProviderException):
                                    self.log.exception(
                                        "Error while getting CheckWX data")
                                else:
                                    self.log.warning(
                                        f"Error while getting CheckWX data: {e}"
                                    )
                                self.add_redis_key(
                                    checkwx_key,
                                    {
                                        "error":
                                        repr(e),
                                        "date":
                                        arrow.now().format(
                                            "YYYY-MM-DD HH:mm:ssZZ"),
                                    },
                                    self.checkwx_cache_duration,
                                )

                        if not self.redis.hexists(checkwx_key, "error"):
                            checkwx_data = json.loads(
                                self.redis.hget(checkwx_key, "data"))

                            station_type = checkwx_data.get("type", None)
                            if station_type:
                                name = f'{checkwx_data["name"]} {station_type}'
                            else:
                                name = checkwx_data["name"]
                            city = checkwx_data.get("city", None)
                            if city:
                                if station_type:
                                    short_name = f"{city} {station_type}"
                                else:
                                    short_name = city
                            else:
                                default_name = checkwx_data["name"]

                            lat = checkwx_data["latitude"]["decimal"]
                            lon = checkwx_data["longitude"]["decimal"]
                            try:
                                tz = checkwx_data["timezone"]["tzid"]
                            except KeyError:
                                raise ProviderException(
                                    "Unable to get the timezone")
                            elevation = checkwx_data.get("elevation", None)
                            altitude = None
                            if elevation:
                                if "meters" in elevation:
                                    altitude = Q_(elevation["meters"],
                                                  ureg.meters)
                                elif "feet" in elevation:
                                    altitude = Q_(elevation["feet"], ureg.feet)

                        if metar.station_id in icao:
                            lat = lat or icao[metar.station_id]["lat"]
                            lon = lon or icao[metar.station_id]["lon"]
                            default_name = default_name or icao[
                                metar.station_id]["name"]

                        station = self.save_station(
                            metar.station_id,
                            short_name,
                            name,
                            lat,
                            lon,
                            StationStatus.GREEN,
                            altitude=altitude,
                            tz=tz,
                            url=os.path.join(
                                self.provider_url,
                                f"site?id={metar.station_id}&db=metar"),
                            default_name=default_name
                            or f"{metar.station_id} Airport",
                            lookup_name=f"{metar.station_id} Airport ICAO",
                        )
                        station_id = station["_id"]

                        if metar.station_id not in icao:
                            self.log.warning(
                                f"Missing '{metar.station_id}' ICAO in database. Is it '{station['name']}'?"
                            )

                        measures_collection = self.measures_collection(
                            station_id)
                        new_measures = []
                        for key in stations[metar_id]:
                            metar = stations[metar_id][key]
                            if not self.has_measure(measures_collection, key):
                                temp = self.get_quantity(
                                    metar.temp, self.temperature_units)
                                dew_point = self.get_quantity(
                                    metar.dewpt, self.temperature_units)
                                humidity = self.compute_humidity(
                                    dew_point, temp)
                                measure = self.create_measure(
                                    station,
                                    key,
                                    self.get_direction(metar.wind_dir),
                                    self.get_quantity(metar.wind_speed,
                                                      self.speed_units),
                                    self.get_quantity(
                                        metar.wind_gust or metar.wind_speed,
                                        self.speed_units),
                                    temperature=temp,
                                    humidity=humidity,
                                    pressure=Pressure(
                                        qfe=None,
                                        qnh=self.get_quantity(
                                            metar.press, self.pressure_units),
                                        qff=self.get_quantity(
                                            metar.press_sea_level,
                                            self.pressure_units),
                                    ),
                                )
                                new_measures.append(measure)

                        self.insert_new_measures(measures_collection, station,
                                                 new_measures)

                    except ProviderException as e:
                        self.log.warning(
                            f"Error while processing station '{metar_id}': {e}"
                        )
                    except Exception as e:
                        self.log.exception(
                            f"Error while processing station '{metar_id}': {e}"
                        )

            except Exception as e:
                self.log.exception(f"Error while processing Metar: {e}")

        self.log.info("Done !")