Esempio n. 1
0
    def calcDerivedVariables(self, device, config, device_type):

        """ Calculate derived variables from available device observations

        INPUTS:
            device              Device ID
            config              Console configuration object
            device_type         Device type
        """

        # Derive variables from available obs_out_air and obs_st observations
        # Derive variables from available obs_out_air and obs_st observations
        if device_type in ('obs_out_air', 'obs_st'):
            self.derive_obs['feelsLike']    = derive.feelsLike(self.device_obs['outTemp'], self.device_obs['humidity'], self.device_obs['windSpd'], config)
            self.derive_obs['dewPoint']     = derive.dewPoint(self.device_obs['outTemp'],  self.device_obs['humidity'])
            self.derive_obs['outTempDiff']  = derive.tempDiff(self.device_obs['outTemp'],  self.device_obs['obTime'], device, self.api_data, config)
            self.derive_obs['outTempTrend'] = derive.tempTrend(self.device_obs['outTemp'], self.device_obs['obTime'], device, self.api_data, config)
            self.derive_obs['outTempMax']   = derive.tempMax(self.device_obs['outTemp'],   self.device_obs['obTime'], self.derive_obs['outTempMax'], device, self.api_data, config)
            self.derive_obs['outTempMin']   = derive.tempMin(self.device_obs['outTemp'],   self.device_obs['obTime'], self.derive_obs['outTempMin'], device, self.api_data, config)
            self.derive_obs['SLP']          = derive.SLP(self.device_obs['pressure'],      device, config)
            self.derive_obs['SLPTrend']     = derive.SLPTrend(self.device_obs['pressure'], self.device_obs['obTime'], device, self.api_data, config)
            self.derive_obs['SLPMax']       = derive.SLPMax(self.device_obs['pressure'],   self.device_obs['obTime'], self.derive_obs['SLPMax'], device, self.api_data, config)
            self.derive_obs['SLPMin']       = derive.SLPMin(self.device_obs['pressure'],   self.device_obs['obTime'], self.derive_obs['SLPMin'], device, self.api_data, config)
            self.derive_obs['strikeCount']  = derive.strikeCount(self.device_obs['strikeMinute'], self.derive_obs['strikeCount'], device, self.api_data, config)
            self.derive_obs['strikeFreq']   = derive.strikeFrequency(self.device_obs['obTime'],   device, self.api_data, config)
            self.derive_obs['strikeDeltaT'] = derive.strikeDeltaT(self.device_obs['strikeTime'])

        # Derive variables from available obs_sky and obs_st observations
        if device_type in ('obs_sky', 'obs_st'):
            self.derive_obs['uvIndex']   = derive.UVIndex(self.device_obs['uvIndex'])
            self.derive_obs['peakSun']   = derive.peakSunHours(self.device_obs['radiation'],  self.derive_obs['peakSun'], device, self.api_data, config)
            self.derive_obs['windSpd']   = derive.beaufortScale(self.device_obs['windSpd'])
            self.derive_obs['windDir']   = derive.cardinalWindDir(self.device_obs['windDir'], self.device_obs['windSpd'])
            self.derive_obs['windAvg']   = derive.avgWindSpeed(self.device_obs['windSpd'],    self.derive_obs['windAvg'], device, self.api_data, config)
            self.derive_obs['gustMax']   = derive.maxWindGust(self.device_obs['windGust'],    self.derive_obs['gustMax'], device, self.api_data, config)
            self.derive_obs['rainRate']  = derive.rainRate(self.device_obs['minuteRain'])
            self.derive_obs['rainAccum'] = derive.rainAccumulation(self.device_obs['dailyRain'], self.derive_obs['rainAccum'], device, self.api_data, config)

        # Derive variables from available obs_out_air and obs_st observations
        if device_type == 'obs_in_air':
            self.derive_obs['inTempMax']   = derive.tempMax(self.device_obs['inTemp'], self.device_obs['obTime'], self.derive_obs['inTempMax'], device, self.api_data, config)
            self.derive_obs['inTempMin']   = derive.tempMin(self.device_obs['inTemp'], self.device_obs['obTime'], self.derive_obs['inTempMin'], device, self.api_data, config)

        # Derive variables from available rapid_wind observations
        if device_type == 'rapid_wind':
            self.derive_obs['rapidWindDir'] = derive.cardinalWindDir(self.device_obs['rapidWindDir'], self.device_obs['rapidWindSpd'])

        # Derive variables from available evt_strike observations
        if device_type == 'evt_strike':
            self.derive_obs['strikeDeltaT'] = derive.strikeDeltaT(self.device_obs['strikeTime'])

        # Format derived observations
        self.format_derived_variables(config, device_type)
def Tempest(Msg, wfpiconsole):
    """ Handles Websocket messages received from TEMPEST module

    INPUTS:
        Msg                 Websocket messages received from TEMPEST module
        wfpiconsole         wfpiconsole object
    """

    # Replace missing observations from latest TEMPEST Websocket JSON with NaN
    Ob = [x if x != None else NaN for x in Msg['obs'][0]]

    # Discard duplicate TEMPEST Websocket messages
    if 'TempestMsg' in wfpiconsole.Obs:
        if wfpiconsole.Obs['TempestMsg']['obs'][0] == Ob[0]:
            print('Discarding duplicate TEMPEST Websocket message')
            return

    # Extract TEMPEST device ID, API flag, and station configuration object
    Device = wfpiconsole.config['Station']['TempestID']
    flagAPI = wfpiconsole.flagAPI[0]
    Config = wfpiconsole.config

    # Extract required observations from latest TEMPEST Websocket JSON
    Time = [Ob[0], 's']
    WindSpd = [Ob[2], 'mps']
    WindGust = [Ob[3], 'mps']
    WindDir = [Ob[4], 'degrees']
    Pres = [Ob[6], 'mb']
    Temp = [Ob[7], 'c']
    Humidity = [Ob[8], '%']
    UV = [Ob[10], 'index']
    Radiation = [Ob[11], 'Wm2']
    Rain = [Ob[12], 'mm']
    Strikes = [Ob[15], 'count']

    # Extract lightning strike data from the latest AIR Websocket JSON "Summary"
    # object
    StrikeTime = [
        Msg['summary']['strike_last_epoch']
        if 'strike_last_epoch' in Msg['summary'] else NaN, 's'
    ]
    StrikeDist = [
        Msg['summary']['strike_last_dist']
        if 'strike_last_dist' in Msg['summary'] else NaN, 'km'
    ]
    Strikes3hr = [
        Msg['summary']['strike_count_3h']
        if 'strike_count_3h' in Msg['summary'] else NaN, 'count'
    ]

    # Store latest TEMPEST Websocket message
    wfpiconsole.Obs['TempestMsg'] = Msg

    # Extract required derived observations
    minPres = wfpiconsole.Obs['MinPres']
    maxPres = wfpiconsole.Obs['MaxPres']
    minTemp = wfpiconsole.Obs['outTempMin']
    maxTemp = wfpiconsole.Obs['outTempMax']
    StrikeCount = {
        'Today': wfpiconsole.Obs['StrikesToday'],
        'Month': wfpiconsole.Obs['StrikesMonth'],
        'Year': wfpiconsole.Obs['StrikesYear']
    }
    rainAccum = {
        'Today': wfpiconsole.Obs['TodayRain'],
        'Yesterday': wfpiconsole.Obs['YesterdayRain'],
        'Month': wfpiconsole.Obs['MonthRain'],
        'Year': wfpiconsole.Obs['YearRain']
    }
    peakSun = wfpiconsole.Obs['peakSun']
    avgWind = wfpiconsole.Obs['AvgWind']
    maxGust = wfpiconsole.Obs['MaxGust']

    # Request TEMPEST data from the previous three hours
    Data3h = requestAPI.weatherflow.Last3h(Device, Time[0], Config)

    # Calculate derived variables from TEMPEST observations
    DewPoint = derive.DewPoint(Temp, Humidity)
    SLP = derive.SLP(Pres, Config)
    PresTrend = derive.SLPTrend(Pres, Time, Data3h, Config)
    FeelsLike = derive.FeelsLike(Temp, Humidity, WindSpd, Config)
    MaxTemp, MinTemp = derive.TempMaxMin(Time, Temp, maxTemp, minTemp, Device,
                                         Config, flagAPI)
    MaxPres, MinPres = derive.SLPMaxMin(Time, Pres, maxPres, minPres, Device,
                                        Config, flagAPI)
    StrikeCount = derive.StrikeCount(Strikes, StrikeCount, Device, Config,
                                     flagAPI)
    StrikeFreq = derive.StrikeFrequency(Time, Data3h, Config)
    StrikeDeltaT = derive.StrikeDeltaT(StrikeTime)
    FeelsLike = derive.FeelsLike(Temp, Humidity, WindSpd, Config)
    RainRate = derive.RainRate(Rain)
    rainAccum = derive.RainAccumulation(Rain, rainAccum, Device, Config,
                                        flagAPI)
    AvgWind = derive.MeanWindSpeed(WindSpd, avgWind, Device, Config, flagAPI)
    MaxGust = derive.MaxWindGust(WindGust, maxGust, Device, Config, flagAPI)
    WindSpd = derive.BeaufortScale(WindSpd)
    WindDir = derive.CardinalWindDirection(WindDir, WindSpd)
    peakSun = derive.peakSunHours(Radiation, peakSun, wfpiconsole.Astro,
                                  Device, Config, flagAPI)
    UVIndex = derive.UVIndex(UV)

    # Convert observation units as required
    Temp = observation.Units(Temp, Config['Units']['Temp'])
    MaxTemp = observation.Units(MaxTemp, Config['Units']['Temp'])
    MinTemp = observation.Units(MinTemp, Config['Units']['Temp'])
    DewPoint = observation.Units(DewPoint, Config['Units']['Temp'])
    FeelsLike = observation.Units(FeelsLike, Config['Units']['Temp'])
    SLP = observation.Units(SLP, Config['Units']['Pressure'])
    MaxPres = observation.Units(MaxPres, Config['Units']['Pressure'])
    MinPres = observation.Units(MinPres, Config['Units']['Pressure'])
    PresTrend = observation.Units(PresTrend, Config['Units']['Pressure'])
    StrikeDist = observation.Units(StrikeDist, Config['Units']['Distance'])
    RainRate = observation.Units(RainRate, Config['Units']['Precip'])
    TodayRain = observation.Units(rainAccum['Today'],
                                  Config['Units']['Precip'])
    YesterdayRain = observation.Units(rainAccum['Yesterday'],
                                      Config['Units']['Precip'])
    MonthRain = observation.Units(rainAccum['Month'],
                                  Config['Units']['Precip'])
    YearRain = observation.Units(rainAccum['Year'], Config['Units']['Precip'])
    WindSpd = observation.Units(WindSpd, Config['Units']['Wind'])
    WindDir = observation.Units(WindDir, Config['Units']['Direction'])
    WindGust = observation.Units(WindGust, Config['Units']['Wind'])
    AvgWind = observation.Units(AvgWind, Config['Units']['Wind'])
    MaxGust = observation.Units(MaxGust, Config['Units']['Wind'])
    FeelsLike = observation.Units(FeelsLike, Config['Units']['Temp'])

    # Store derived TEMPEST observations in dictionary
    derivedObs = {}
    derivedObs['outTemp'] = observation.Format(Temp, 'Temp')
    derivedObs['outTempMax'] = observation.Format(MaxTemp, 'Temp')
    derivedObs['outTempMin'] = observation.Format(MinTemp, 'Temp')
    derivedObs['DewPoint'] = observation.Format(DewPoint, 'Temp')
    derivedObs['FeelsLike'] = observation.Format(FeelsLike, 'Temp')
    derivedObs['Pres'] = observation.Format(SLP, 'Pressure')
    derivedObs['MaxPres'] = observation.Format(MaxPres, 'Pressure')
    derivedObs['MinPres'] = observation.Format(MinPres, 'Pressure')
    derivedObs['PresTrend'] = observation.Format(PresTrend, 'Pressure')
    derivedObs['StrikeDeltaT'] = observation.Format(StrikeDeltaT, 'TimeDelta')
    derivedObs['StrikeDist'] = observation.Format(StrikeDist, 'StrikeDistance')
    derivedObs['StrikeFreq'] = observation.Format(StrikeFreq,
                                                  'StrikeFrequency')
    derivedObs['Strikes3hr'] = observation.Format(Strikes3hr, 'StrikeCount')
    derivedObs['StrikesToday'] = observation.Format(StrikeCount['Today'],
                                                    'StrikeCount')
    derivedObs['StrikesMonth'] = observation.Format(StrikeCount['Month'],
                                                    'StrikeCount')
    derivedObs['StrikesYear'] = observation.Format(StrikeCount['Year'],
                                                   'StrikeCount')
    derivedObs['Humidity'] = observation.Format(Humidity, 'Humidity')
    derivedObs['FeelsLike'] = observation.Format(FeelsLike, 'Temp')
    derivedObs['RainRate'] = observation.Format(RainRate, 'Precip')
    derivedObs['TodayRain'] = observation.Format(TodayRain, 'Precip')
    derivedObs['YesterdayRain'] = observation.Format(YesterdayRain, 'Precip')
    derivedObs['MonthRain'] = observation.Format(MonthRain, 'Precip')
    derivedObs['YearRain'] = observation.Format(YearRain, 'Precip')
    derivedObs['WindSpd'] = observation.Format(WindSpd, 'Wind')
    derivedObs['WindGust'] = observation.Format(WindGust, 'Wind')
    derivedObs['AvgWind'] = observation.Format(AvgWind, 'Wind')
    derivedObs['MaxGust'] = observation.Format(MaxGust, 'Wind')
    derivedObs['WindDir'] = observation.Format(WindDir, 'Direction')
    derivedObs['Radiation'] = observation.Format(Radiation, 'Radiation')
    derivedObs['peakSun'] = observation.Format(peakSun, 'peakSun')
    derivedObs['UVIndex'] = observation.Format(UVIndex, 'UV')

    # Update wfpiconsole display with derived TEMPEST observations
    updateDisplay(derivedObs, wfpiconsole, 'Tempest')

    # Set flags for required API calls
    wfpiconsole.flagAPI[0] = 0

    # Return wfpiconsole object
    return wfpiconsole
def outdoorAir(Msg, wfpiconsole):
    """ Handles Websocket messages received from outdoor AIR module

    INPUTS:
        Msg                 Websocket messages received from outdoor AIR module
        wfpiconsole         wfpiconsole object
    """

    # Replace missing observations in latest outdoor AIR Websocket JSON with NaN
    Ob = [x if x != None else NaN for x in Msg['obs'][0]]

    # Discard duplicate outdoor AIR Websocket messages
    if 'outAirMsg' in wfpiconsole.Obs:
        if wfpiconsole.Obs['outAirMsg']['obs'][0] == Ob[0]:
            print('Discarding duplicate outdoor AIR Websocket message')
            return

    # Extract outdoor AIR device ID and API flag, and station configuration
    # object
    Device = wfpiconsole.config['Station']['OutAirID']
    flagAPI = wfpiconsole.flagAPI[2]
    Config = wfpiconsole.config

    # Extract required observations from latest outdoor AIR Websocket JSON
    Time = [Ob[0], 's']
    Pres = [Ob[1], 'mb']
    Temp = [Ob[2], 'c']
    Humidity = [Ob[3], '%']
    Strikes = [Ob[4], 'count']

    # Extract lightning strike data from the latest outdoor AIR Websocket JSON
    # "Summary" object
    StrikeTime = [
        Msg['summary']['strike_last_epoch']
        if 'strike_last_epoch' in Msg['summary'] else NaN, 's'
    ]
    StrikeDist = [
        Msg['summary']['strike_last_dist']
        if 'strike_last_dist' in Msg['summary'] else NaN, 'km'
    ]
    Strikes3hr = [
        Msg['summary']['strike_count_3h']
        if 'strike_count_3h' in Msg['summary'] else NaN, 'count'
    ]

    # Extract required derived observations
    minPres = wfpiconsole.Obs['MinPres']
    maxPres = wfpiconsole.Obs['MaxPres']
    minTemp = wfpiconsole.Obs['outTempMin']
    maxTemp = wfpiconsole.Obs['outTempMax']
    StrikeCount = {
        'Today': wfpiconsole.Obs['StrikesToday'],
        'Month': wfpiconsole.Obs['StrikesMonth'],
        'Year': wfpiconsole.Obs['StrikesYear']
    }

    # Request outdoor AIR data from the previous three hours
    Data3h = requestAPI.weatherflow.Last3h(Device, Time[0], Config)

    # Store latest outdoor AIR Websocket message
    wfpiconsole.Obs['outAirMsg'] = Msg

    # Extract required observations from latest SKY Websocket JSON
    while not 'SkyMsg' in wfpiconsole.Obs:
        time.sleep(0.01)
    Ob = [x if x != None else NaN for x in wfpiconsole.Obs['SkyMsg']['obs'][0]]
    WindSpd = [Ob[5], 'mps']

    # Calculate derived variables from AIR observations
    DewPoint = derive.DewPoint(Temp, Humidity)
    SLP = derive.SLP(Pres, Config)
    PresTrend = derive.SLPTrend(Pres, Time, Data3h, Config)
    FeelsLike = derive.FeelsLike(Temp, Humidity, WindSpd, Config)
    MaxTemp, MinTemp = derive.TempMaxMin(Time, Temp, maxTemp, minTemp, Device,
                                         Config, flagAPI)
    MaxPres, MinPres = derive.SLPMaxMin(Time, Pres, maxPres, minPres, Device,
                                        Config, flagAPI)
    StrikeCount = derive.StrikeCount(Strikes, StrikeCount, Device, Config,
                                     flagAPI)
    StrikeFreq = derive.StrikeFrequency(Time, Data3h, Config)
    StrikeDeltaT = derive.StrikeDeltaT(StrikeTime)

    # Convert observation units as required
    Temp = observation.Units(Temp, Config['Units']['Temp'])
    MaxTemp = observation.Units(MaxTemp, Config['Units']['Temp'])
    MinTemp = observation.Units(MinTemp, Config['Units']['Temp'])
    DewPoint = observation.Units(DewPoint, Config['Units']['Temp'])
    FeelsLike = observation.Units(FeelsLike, Config['Units']['Temp'])
    SLP = observation.Units(SLP, Config['Units']['Pressure'])
    MaxPres = observation.Units(MaxPres, Config['Units']['Pressure'])
    MinPres = observation.Units(MinPres, Config['Units']['Pressure'])
    PresTrend = observation.Units(PresTrend, Config['Units']['Pressure'])
    StrikeDist = observation.Units(StrikeDist, Config['Units']['Distance'])

    # Store derived outdoor AIR observations in dictionary
    derivedObs = {}
    derivedObs['outTemp'] = observation.Format(Temp, 'Temp')
    derivedObs['outTempMax'] = observation.Format(MaxTemp, 'Temp')
    derivedObs['outTempMin'] = observation.Format(MinTemp, 'Temp')
    derivedObs['DewPoint'] = observation.Format(DewPoint, 'Temp')
    derivedObs['FeelsLike'] = observation.Format(FeelsLike, 'Temp')
    derivedObs['Pres'] = observation.Format(SLP, 'Pressure')
    derivedObs['MaxPres'] = observation.Format(MaxPres, 'Pressure')
    derivedObs['MinPres'] = observation.Format(MinPres, 'Pressure')
    derivedObs['PresTrend'] = observation.Format(PresTrend, 'Pressure')
    derivedObs['StrikeDeltaT'] = observation.Format(StrikeDeltaT, 'TimeDelta')
    derivedObs['StrikeDist'] = observation.Format(StrikeDist, 'StrikeDistance')
    derivedObs['StrikeFreq'] = observation.Format(StrikeFreq,
                                                  'StrikeFrequency')
    derivedObs['Strikes3hr'] = observation.Format(Strikes3hr, 'StrikeCount')
    derivedObs['StrikesToday'] = observation.Format(StrikeCount['Today'],
                                                    'StrikeCount')
    derivedObs['StrikesMonth'] = observation.Format(StrikeCount['Month'],
                                                    'StrikeCount')
    derivedObs['StrikesYear'] = observation.Format(StrikeCount['Year'],
                                                   'StrikeCount')
    derivedObs['Humidity'] = observation.Format(Humidity, 'Humidity')

    # Update wfpiconsole display with derived outdoor AIR observations
    updateDisplay(derivedObs, wfpiconsole, 'outdoorAir')

    # Set flags for required API calls
    wfpiconsole.flagAPI[2] = 0

    # Return wfpiconsole object
    return wfpiconsole
Esempio n. 4
0
def SLPMaxMin(Time, Pres, maxPres, minPres, Device, Config, flagAPI):
    """ Calculate maximum and minimum pressure since midnight station time

    INPUTS:
        Time                Current observation time        [s]
        Temp                Current pressure                [mb]
        maxPres             Current maximum pressure        [mb]
        minPres             Current minimum pressure        [mb]
        Device              Device ID
        Config              Station configuration
        flagAPI             Flag for required API calls

    OUTPUT:
        MaxTemp             Maximum pressure                [mb]
        MinTemp             Minumum pressure                [mb]
    """

    # Calculate sea level pressure
    SLP = derive.SLP(Pres, Config)

    # Define current time in station timezone
    Tz = pytz.timezone(Config['Station']['Timezone'])
    Now = datetime.now(pytz.utc).astimezone(Tz)

    # Set time format based on user configuration
    if Config['Display']['TimeFormat'] == '12 hr':
        if Config['System']['Hardware'] != 'Other':
            Format = '%-I:%M %P'
        else:
            Format = '%I:%M %p'
    else:
        Format = '%H:%M'

    # If console is initialising, download all data for current day using
    # Weatherflow API and calculate daily maximum and minimum pressure
    if maxPres[0] == '-' or flagAPI:

        # Download pressure data from the current day
        Data = requestAPI.weatherflow.Today(Device, Config)

        # Calculate maximum and minimum pressure. Return NaN if API call fails
        if requestAPI.weatherflow.verifyResponse(Data, 'obs'):

            # Extract data from API call based on device type
            Data = Data.json()['obs']
            Time = [item[0] for item in Data if item[0] != None]
            if Config['Station']['OutAirID']:
                Pres = [[item[1], 'mb'] for item in Data if item[1] != None]
            elif Config['Station']['TempestID']:
                Pres = [[item[6], 'mb'] for item in Data if item[6] != None]

            # Calculate sea level pressure
            SLP = [derive.SLP(P, Config) for P in Pres]

            # Define maximum and minimum pressure
            if len(SLP) > 0:
                MaxPres = [
                    max(SLP)[0], 'mb',
                    datetime.fromtimestamp(Time[SLP.index(max(SLP))],
                                           Tz).strftime(Format),
                    max(SLP)[0], Now
                ]
                MinPres = [
                    min(SLP)[0], 'mb',
                    datetime.fromtimestamp(Time[SLP.index(min(SLP))],
                                           Tz).strftime(Format),
                    min(SLP)[0], Now
                ]
            else:
                MaxPres = [NaN, 'mb', '-', NaN, Now]
                MinPres = [NaN, 'mb', '-', NaN, Now]
        else:
            MaxPres = [NaN, 'mb', '-', NaN, Now]
            MinPres = [NaN, 'mb', '-', NaN, Now]

    # Else if midnight has passed, reset maximum and minimum pressure
    elif Now.date() > maxPres[4].date():
        MaxPres = [
            SLP[0], 'mb',
            datetime.fromtimestamp(Time[0], Tz).strftime(Format), SLP[0], Now
        ]
        MinPres = [
            SLP[0], 'mb',
            datetime.fromtimestamp(Time[0], Tz).strftime(Format), SLP[0], Now
        ]

    # Else if current pressure is greater than maximum recorded pressure, update
    # maximum pressure
    elif SLP[0] > maxPres[3]:
        MaxPres = [
            SLP[0], 'mb',
            datetime.fromtimestamp(Time[0], Tz).strftime(Format), SLP[0], Now
        ]
        MinPres = [minPres[3], 'mb', minPres[2], minPres[3], Now]

    # Else if current pressure is less than minimum recorded pressure, update
    # minimum pressure and time
    elif SLP[0] < minPres[3]:
        MaxPres = [maxPres[3], 'mb', maxPres[2], maxPres[3], Now]
        MinPres = [
            SLP[0], 'mb',
            datetime.fromtimestamp(Time[0], Tz).strftime(Format), SLP[0], Now
        ]

    # Else maximum and minimum pressure unchanged, return existing values
    else:
        MaxPres = [maxPres[3], 'mb', maxPres[2], maxPres[3], Now]
        MinPres = [minPres[3], 'mb', minPres[2], minPres[3], Now]

    # Return required variables
    return MaxPres, MinPres