def _make_wind(weather_object):
    if not weather_object.metar_data.wind_speed:
        LOGGER.warning(
            'no wind speed data found in METAR, using triangular randomized wind speed '
            '(low=0, high=25, mode= 7) [knots]')
        weather_object.wind_speed = WindSpeed(random.triangular(0, 25, mode=7),
                                              'kt')  # nosec
    else:
        weather_object.wind_speed = WindSpeed(
            weather_object.metar_data.wind_speed.value,
            weather_object.metar_units.wind_speed)
    if not weather_object.metar_data.wind_direction:
        LOGGER.warning(
            'no wind direction data found in METAR, using random wind direction'
            '(between 0 and 359) [degrees]')
        weather_object.wind_direction = WindDirection(random.randint(
            0, 359))  # nosec
    else:
        if weather_object.metar_data.wind_direction.repr == 'VRB':
            weather_object.wind_direction_is_variable = True
        weather_object.wind_direction = WindDirection(
            weather_object.metar_data.wind_direction.value)
    weather_object.wind_direction_range = [
        WindDirection(wind_dir.value)
        for wind_dir in weather_object.metar_data.wind_variable_direction
    ]
    if weather_object.metar_data.wind_gust:
        weather_object.wind_gust = WindSpeed(
            weather_object.metar_data.wind_gust.value,
            weather_object.metar_units.wind_speed)
    else:
        weather_object.wind_gust = WindSpeed(0)
Example #2
0
def _make_clouds(weather_object) -> typing.Tuple[int, int, int]:
    cloud_density = 0
    cloud_base = 300
    cloud_thickness = 200
    _layer_in_use = None
    for _layer in weather_object.cloud_layers:
        _coverage = random.randint(*CLOUD_METAR_TO_DCS[_layer.type])  # nosec
        if _coverage > cloud_density:
            cloud_density = _coverage
            _layer_in_use = _layer
    if _layer_in_use:
        LOGGER.debug('using cloud layer: %s', _layer_in_use.repr)
        if not _layer_in_use.altitude:
            LOGGER.warning(
                'no cloud altitude data found in METAR, using random number between 5 and 35 thousand feet'
            )
            cloud_base = random.randint(5, 25) * 1000  # nosec
        else:
            if not weather_object.metar_units.altitude == 'ft':
                raise ValueError(weather_object.metar_units.altitude)
            cloud_base = CloudBase(_layer_in_use.altitude * 100, 'ft').value('m')
        cloud_thickness = int(cloud_density / 10 * 2000)
    else:
        LOGGER.debug('no clouds')

    cloud_base = DCSWeather.normalize_cloud_base(cloud_base)
    cloud_thickness = DCSWeather.normalize_cloud_thickness(cloud_thickness)

    return cloud_base, cloud_density, cloud_thickness
def _make_altimeter(weather_object):
    if not weather_object.metar_data.altimeter:
        LOGGER.warning(
            'no altimeter data found in METAR, using triangular randomized pressure '
            '(low=720, high=790, mode= 760) [mmHg]')
        weather_object.altimeter = Pressure(
            int(random.triangular(720, 790, mode=760)))  # nosec
    else:
        weather_object.altimeter = Pressure(
            weather_object.metar_data.altimeter.value,
            weather_object.metar_units.altimeter)
def _make_dew_point(weather_object):
    if weather_object.metar_data.dewpoint:
        weather_object.dew_point = Temperature(
            weather_object.metar_data.dewpoint.value,
            weather_object.metar_units.temperature)
    else:
        LOGGER.warning(
            'no dew point data found in METAR, creating dummy dew point from temperature'
        )
        weather_object.dew_point = weather_object.temperature.make_dummy_dew_point(
        )
 def normalize_turbulence(value: float) -> int:
     """
     Enforces DCS constraints for turbulence value
     """
     if value < 0:
         LOGGER.warning('turbulence value is too low, normalizing to 0')
         return 0
     if value > 60:
         LOGGER.warning('temperature value is too high, normalizing to 60')
         return 60
     return int(round(value, 0))
def _make_temperature(weather_object):
    if weather_object.metar_data.temperature:
        weather_object.temperature = Temperature(
            weather_object.metar_data.temperature.value,
            weather_object.metar_units.temperature)
    else:
        LOGGER.warning(
            'no temperature value found in METAR, using triangular randomized temperature '
            '(low=-10, high=40, mode= 18) [degrees Celsius]')
        weather_object.temperature = Temperature(
            round(int(random.triangular(-10, 40, mode=18)), 0), 'c')  # nosec
 def normalize_wind_speed(value: float,
                          name: typing.Optional[str] = 'wind speed') -> int:
     """
     Enforces DCS constraints for wind speed value
     """
     if value < 0:
         LOGGER.warning('%s is too low, normalizing to 0 m/s', name)
         return 0
     if value > 50:
         LOGGER.warning('%s is too high, normalizing to 50 m/s', name)
         return 50
     return int(value)
 def normalize_cloud_base(value: float) -> int:
     """
     Enforces DCS constraints for cloud base value
     """
     if value < 300:
         LOGGER.warning(
             'cloud base value is too low, normalizing to 300 meters')
         return 300
     if value > 5000:
         LOGGER.warning(
             'cloud base value is too high, normalizing to 5000 meters')
         return 5000
     return int(value)
 def normalize_fog_visibility(value: float) -> int:
     """
     Enforces DCS constraints for fog visibility value
     """
     if value < 0:
         LOGGER.warning(
             'fog visibility value is too low, normalizing to 0 meters')
         return 0
     if value > 6000:
         LOGGER.warning(
             'fog visibility value is too high, normalizing to 6000 meters')
         return 6000
     return int(value)
Example #10
0
 def normalize_dust_density(value: float) -> int:
     """
     Enforces DCS constraints for dust density value
     """
     if value < 300:
         LOGGER.warning(
             'dust density value is too low, normalizing to 300 meters')
         return 300
     if value > 3000:
         LOGGER.warning(
             'dust density value is too high, normalizing to 3000 meters')
         return 3000
     return int(value)
Example #11
0
 def normalize_temperature(value: float) -> int:
     """
     Enforces DCS constraints for temperature value
     """
     if value < -20:
         LOGGER.warning(
             'temperature value is too low, normalizing to -20° Celsius')
         return -20
     if value > 40:
         LOGGER.warning(
             'temperature value is too high, normalizing to 40° Celsius')
         return 40
     return int(value)
Example #12
0
 def normalize_altimeter(value: float) -> int:
     """
     Enforces DCS constraints for altimeter value
     """
     if value < 720:
         LOGGER.warning(
             'altimeter value is too low, normalizing to 720 mmHg')
         return 720
     if value > 790:
         LOGGER.warning(
             'altimeter value is too high, normalizing to 790 mmHg')
         return 790
     return int(value)
Example #13
0
def _make_dust(weather_object) -> typing.Tuple[bool, int]:
    dust_enabled = False
    dust_density = 3000
    for _dust_indicator in {'DU', 'DS', 'PO', 'SS'}:
        if any(_dust_indicator in other for other in weather_object.metar_data.other):
            if weather_object.visibility.value() > 5000:
                LOGGER.debug('there is dust in the area but visibility is over 5000m, not adding dust')
                break
            else:
                LOGGER.warning('there is dust in the area, visibility will be severely restricted')
                dust_enabled = True
                dust_density = DCSWeather.normalize_dust_density(weather_object.visibility.value())
                break
    return dust_enabled, dust_density
Example #14
0
 def normalize_cloud_thickness(value: float) -> int:
     """
     Enforces DCS constraints for cloud thickness value
     """
     if value < 200:
         LOGGER.warning(
             'cloud thickness value is too low, normalizing to 200 meters')
         return 200
     if value > 2000:
         LOGGER.warning(
             'cloud thickness value is too high, normalizing to 2000 meters'
         )
         return 2000
     return int(value)
def _make_visibility(weather_object):
    if not weather_object.metar_data.visibility:
        LOGGER.warning(
            'no visibility data found in METAR, using triangular randomized visibility '
            '(low=2000, high=20000, mode= 15000) [meters]')
        weather_object.visibility = Visibility(
            min((round(int(random.triangular(2000, 20000, mode=15000)),
                       -2), 9999)))  # nosec
    else:
        if weather_object.metar_data.visibility.repr == 'P6':
            weather_object.visibility = Visibility(9999, 'm')
        elif weather_object.metar_data.visibility.repr == 'M1/4':
            weather_object.visibility = Visibility(400, 'm')
        else:
            weather_object.visibility = Visibility(
                weather_object.metar_data.visibility.value,
                weather_object.metar_units.visibility)
Example #16
0
 def _as_str(self, spoken: bool) -> str:
     intro = self._make_str_intro(spoken=spoken)
     wind = self._wind_as_str(spoken=spoken)
     visibility = self._visibility_as_str(spoken=spoken)
     temperature = self._temperature_as_str(spoken=spoken)
     dew_point = self._dew_point_as_str(spoken=spoken)
     altimeter = self._altimeter_as_str(spoken=spoken)
     other = self._others_as_str()
     clouds = self._clouds_as_str(spoken=spoken)
     try:
         remarks = self._remarks_as_str(spoken=spoken) or ''
     except (IndexError, ValueError):
         LOGGER.warning('failed to parse remarks: %s', self.remarks)
         remarks = ''
     _result = [intro, wind, visibility, temperature, dew_point, altimeter, other, clouds, remarks]
     _result = [x for x in _result if x != '']
     result = ' '.join(_result)
     return result.replace('  ', ' ')
Example #17
0
def _parse_cloud_layer_as_str(self, cloud, ret: list, spoken: bool):
    if cloud.altitude is None:
        LOGGER.warning('no altitude given, skipping cloud layer: %s',
                       cloud.repr)
        return
    cloud_str = static.CLOUD_TRANSLATIONS[cloud.type]
    if cloud.modifier:
        try:
            cloud_str += f' ({static.CLOUD_TRANSLATIONS[cloud.modifier]})'
        except KeyError:
            LOGGER.warning('unknown cloud modifier: %s', cloud.modifier)
    altitude_as_str = str(cloud.altitude)
    while len(altitude_as_str) != 3:
        altitude_as_str = '0' + altitude_as_str
    if spoken:
        cloud_alt = []

        _cloud_alt_in_thousand_feet_str = int(cloud.altitude / 10)

        if _cloud_alt_in_thousand_feet_str > 0:
            cloud_alt.append(
                utils.num_to_words(_cloud_alt_in_thousand_feet_str, group=0) +
                ' thousand')

        clouds_altitude_hundreds = altitude_as_str[2]
        if clouds_altitude_hundreds != '0':
            cloud_alt.append(
                utils.num_to_words(clouds_altitude_hundreds, group=0))
            cloud_alt.append('hundred')

        cloud_alt.append('feet')
        ret.append(cloud_str.format(' '.join(cloud_alt)))
    else:
        cloud_base = Altitude(cloud.altitude * 100, self.metar_units.altitude)
        ret.append(
            cloud_str.format(cloud_base.to_string(unit='ft', spoken=spoken)))
Example #18
0
def _make_precipitations(weather_object, temperature, cloud_density) -> typing.Tuple[int, int, int]:
    precipitation_code = 0
    for phenomenon in WEATHER_PHENOMENONS:
        for indicator in phenomenon.indicators:
            if any(indicator in other for other in weather_object.metar_data.other):
                precipitation_code = phenomenon.precipitation_code
                LOGGER.warning('%s reported in the area', phenomenon.name)
                if phenomenon.min_temp is not None and temperature < phenomenon.min_temp:
                    LOGGER.warning('forcing temperature to %s due to %s', phenomenon.min_temp, phenomenon.name)
                    temperature = phenomenon.min_temp
                if phenomenon.max_temp is not None and temperature > phenomenon.max_temp:
                    LOGGER.warning('forcing temperature to %s due to %s', phenomenon.max_temp, phenomenon.name)
                    temperature = phenomenon.max_temp
                if cloud_density < phenomenon.min_cloud_density:
                    LOGGER.warning('forcing cloud density to %s due to %s',
                                   phenomenon.min_cloud_density, phenomenon.name)
                    cloud_density = phenomenon.min_cloud_density
                break

    return precipitation_code, temperature, cloud_density