def parse_noon_forecast(station_code, forecast) -> NoonForecast: """ Transform from the raw forecast json object returned by wf1, to our noon forecast object. """ timestamp = datetime.fromtimestamp( int(forecast['weatherTimestamp']) / 1000, tz=timezone.utc).isoformat() noon_forecast = NoonForecast( weather_date=timestamp, created_at=get_utc_now(), wfwx_update_date=forecast.get('updateDate', None), station_code=station_code, temperature=forecast.get('temperature', math.nan), relative_humidity=forecast.get('relativeHumidity', math.nan), wind_speed=forecast.get('windSpeed', math.nan), wind_direction=forecast.get('windDirection', math.nan), precipitation=forecast.get('precipitation', math.nan), gc=forecast.get('grasslandCuring', math.nan), ffmc=forecast.get('fineFuelMoistureCode', math.nan), dmc=forecast.get('duffMoistureCode', math.nan), dc=forecast.get('droughtCode', math.nan), isi=forecast.get('initialSpreadIndex', math.nan), bui=forecast.get('buildUpIndex', math.nan), fwi=forecast.get('fireWeatherIndex', math.nan), ) temp_valid, rh_valid, wdir_valid, wspeed_valid, precip_valid = get_valid_flags(noon_forecast) noon_forecast.temp_valid = temp_valid noon_forecast.rh_valid = rh_valid noon_forecast.wdir_valid = wdir_valid noon_forecast.wspeed_valid = wspeed_valid noon_forecast.precip_valid = precip_valid return noon_forecast
def test_wind_speed_valid(): """ 0 to inf is valid for wind_speed""" low_valid = WeatherReading(temperature=None, relative_humidity=None, wind_speed=0, wind_direction=None, precipitation=None) _, _, low_wind_speed_valid, _, _ = get_valid_flags(low_valid) assert low_wind_speed_valid is True high_valid = WeatherReading(temperature=None, relative_humidity=None, wind_speed=math.inf, wind_direction=None, precipitation=None) _, _, high_wind_speed_valid, _, _ = get_valid_flags(high_valid) assert high_wind_speed_valid is True
def test_rh_invalid(): """ Below 0 and above 100 is invalid for rh""" low_valid = WeatherReading(temperature=None, relative_humidity=-1, wind_speed=None, wind_direction=None, precipitation=None) _, low_rh_invalid, _, _, _ = get_valid_flags(low_valid) assert low_rh_invalid is False high_valid = WeatherReading(temperature=None, relative_humidity=101, wind_speed=None, wind_direction=None, precipitation=None) _, high_rh_invalid, _, _, _ = get_valid_flags(high_valid) assert high_rh_invalid is False
def test_rh_valid(): """ 0 to 100 is valid for rh""" low_valid = WeatherReading(temperature=None, relative_humidity=0, wind_speed=None, wind_direction=None, precipitation=None) _, low_rh_valid, _, _, _ = get_valid_flags(low_valid) assert low_rh_valid is True high_valid = WeatherReading(temperature=None, relative_humidity=100, wind_speed=None, wind_direction=None, precipitation=None) _, high_rh_valid, _, _, _ = get_valid_flags(high_valid) assert high_rh_valid is True
def test_temp_invalid(): """ No temp number is invalid""" test_record = WeatherReading(temperature=None, relative_humidity=None, wind_speed=None, wind_direction=None, precipitation=None) temp_valid, _, _, _, _ = get_valid_flags(test_record) assert temp_valid is False
def test_precip_invalid(): """ Below 0 is invalid for precip""" low_valid = WeatherReading(temperature=None, relative_humidity=None, wind_speed=None, wind_direction=None, precipitation=-1) _, _, _, _, low_precip_invalid = get_valid_flags(low_valid) assert low_precip_invalid is False
def parse_hourly_actual(station_code: int, hourly): """ Transform from the raw hourly json object returned by wf1, to our hour actual object. """ timestamp = datetime.fromtimestamp( int(hourly['weatherTimestamp']) / 1000, tz=timezone.utc).isoformat() hourly_actual = HourlyActual( weather_date=timestamp, station_code=station_code, temperature=hourly.get('temperature', math.nan), relative_humidity=hourly.get('relativeHumidity', math.nan), dewpoint=compute_dewpoint(hourly.get( 'temperature'), hourly.get('relativeHumidity')), wind_speed=hourly.get('windSpeed', math.nan), wind_direction=hourly.get('windDirection', math.nan), precipitation=hourly.get('precipitation', math.nan), ffmc=hourly.get('fineFuelMoistureCode', None), isi=hourly.get('initialSpreadIndex', None), fwi=hourly.get('fireWeatherIndex', None), ) temp_valid, rh_valid, wdir_valid, wspeed_valid, precip_valid = get_valid_flags(hourly_actual) hourly_actual.temp_valid = temp_valid hourly_actual.rh_valid = rh_valid hourly_actual.wdir_valid = wdir_valid hourly_actual.wspeed_valid = wspeed_valid hourly_actual.precip_valid = precip_valid observation_valid = hourly.get('observationValidInd') observation_valid_comment = hourly.get('observationValidComment') if observation_valid is None or bool(observation_valid) is False: logger.warning("Invalid hourly received from WF1 API for station code %s at time %s: %s", station_code, hourly_actual.weather_date, observation_valid_comment) is_obs_invalid = not temp_valid and not rh_valid and not wdir_valid\ and not wspeed_valid and not precip_valid if is_obs_invalid: logger.error("Hourly actual not written to DB for station code %s at time %s: %s", station_code, hourly_actual.weather_date, observation_valid_comment) # don't write the HourlyActual to our database if every value is invalid. If even one # weather variable observed is valid, write the HourlyActual to DB. return None if is_obs_invalid else hourly_actual