def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None): """Get a series, possibly with aggregation, for special 'wind vector' types. These are typically used for the wind vector plots. """ # Check to see if the requested type is not 'windvec' or 'windgustvec' if obs_type not in WindVec.windvec_types: # The type is not one of the extended wind types. We can't handle it. raise weewx.UnknownType(obs_type) # It is an extended wind type. Prepare the lists that will hold the # final results. start_vec = list() stop_vec = list() data_vec = list() # Is aggregation requested? if aggregate_type: # Yes. Just use the regular series function. When it comes time to do the aggregation, # the specialized function WindVec.get_aggregate() (defined below), will be used. return ArchiveTable.get_series(obs_type, timespan, db_manager, aggregate_type, aggregate_interval) else: # No aggregation desired. However, we have will have to assemble the wind vector from # its flattened types. This SQL select string will select the proper wind types sql_str = 'SELECT dateTime, %s, %s, usUnits, `interval` FROM %s ' \ 'WHERE dateTime >= ? AND dateTime <= ?' \ % (WindVec.windvec_types[obs_type][0], WindVec.windvec_types[obs_type][1], db_manager.table_name) std_unit_system = None for record in db_manager.genSql(sql_str, timespan): ts, magnitude, direction, unit_system, interval = record if std_unit_system: if std_unit_system != unit_system: raise weewx.UnsupportedFeature( "Unit type cannot change within a time interval.") else: std_unit_system = unit_system value = weeutil.weeutil.to_complex(magnitude, direction) start_vec.append(ts - interval * 60) stop_vec.append(ts) data_vec.append(value) unit, unit_group = weewx.units.getStandardUnitType( std_unit_system, obs_type, aggregate_type) return (ValueTuple(start_vec, 'unix_epoch', 'group_time'), ValueTuple(stop_vec, 'unix_epoch', 'group_time'), ValueTuple(data_vec, unit, unit_group))
def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None): """Get a series, possibly with aggregation. """ if obs_type not in [ 'pm2_5_aqi', 'pm2_5_aqi_color' ]: raise weewx.UnknownType(obs_type) log.debug('get_series(%s, %s, %s, aggregate:%s, aggregate_interval:%s)' % ( obs_type, timestamp_to_string(timespan.start), timestamp_to_string( timespan.stop), aggregate_type, aggregate_interval)) # Prepare the lists that will hold the final results. start_vec = list() stop_vec = list() data_vec = list() # Is aggregation requested? if aggregate_type: # Yes. Just use the regular series function. return weewx.xtypes.ArchiveTable.get_series(obs_type, timespan, db_manager, aggregate_type, aggregate_interval) else: # No aggregation. sql_str = 'SELECT dateTime, usUnits, `interval`, pm2_5 FROM %s ' \ 'WHERE dateTime >= ? AND dateTime <= ? AND pm2_5 IS NOT NULL' \ % db_manager.table_name std_unit_system = None for record in db_manager.genSql(sql_str, timespan): ts, unit_system, interval, pm2_5 = record if std_unit_system: if std_unit_system != unit_system: raise weewx.UnsupportedFeature( "Unit type cannot change within a time interval.") else: std_unit_system = unit_system if obs_type == 'pm2_5_aqi': value = AQI.compute_pm2_5_aqi(pm2_5) if obs_type == 'pm2_5_aqi_color': value = AQI.compute_pm2_5_aqi_color(AQI.compute_pm2_5_aqi(pm2_5)) log.debug('get_series(%s): %s - %s - %s' % (obs_type, timestamp_to_string(ts - interval * 60), timestamp_to_string(ts), value)) start_vec.append(ts - interval * 60) stop_vec.append(ts) data_vec.append(value) unit, unit_group = weewx.units.getStandardUnitType(std_unit_system, obs_type, aggregate_type) return (ValueTuple(start_vec, 'unix_epoch', 'group_time'), ValueTuple(stop_vec, 'unix_epoch', 'group_time'), ValueTuple(data_vec, unit, unit_group))
def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None): """Get a series, possibly with aggregation, for special 'wind' types.""" # Check to see if the requested type is not 'windvec' or 'windgustvec' if obs_type not in Wind.windvec_types: # The type is not one of the extended wind types. We can't handle it. raise weewx.UnknownType(obs_type) # It is an extended wind type. Prepare the lists that will hold the # final results. start_vec = list() stop_vec = list() data_vec = list() # Is aggregation requested? if aggregate_type: # Yes. Just use the regular series function, but with the special wind aggregate type. It will # call the proper aggregation function. return SeriesArchive.get_series(obs_type, timespan, db_manager, aggregate_type, aggregate_interval) else: # No aggregation desired. However, we have will have to assemble the wind vector from its flattened types. # This SQL select string will select the proper wind types sql_str = 'SELECT dateTime, %s, %s, usUnits, `interval` FROM %s WHERE dateTime >= ? AND dateTime <= ?' \ % (Wind.windvec_types[obs_type][0], Wind.windvec_types[obs_type][1], db_manager.table_name) std_unit_system = None for record in db_manager.genSql(sql_str, timespan): start_vec.append(record[0] - record[4] * 60) stop_vec.append(record[0]) if std_unit_system: if std_unit_system != record[3]: raise weewx.UnsupportedFeature("Unit type cannot change within a time interval.") else: std_unit_system = record[3] # Break the mag and dir down into x- and y-components. (magnitude, direction) = record[1:3] if magnitude is None or direction is None: data_vec.append(None) else: x = magnitude * math.cos(math.radians(90.0 - direction)) y = magnitude * math.sin(math.radians(90.0 - direction)) if weewx.debug: # There seem to be some little rounding errors that # are driving my debugging crazy. Zero them out if abs(x) < 1.0e-6: x = 0.0 if abs(y) < 1.0e-6: y = 0.0 data_vec.append(complex(x, y)) unit, unit_group = weewx.units.getStandardUnitType(std_unit_system, obs_type, aggregate_type) return (ValueTuple(start_vec, 'unix_epoch', 'group_time'), ValueTuple(stop_vec, 'unix_epoch', 'group_time'), ValueTuple(data_vec, unit, unit_group))
def get_vectors(self, stamps, csv_file_name, threshold_lo_t, threshold_hi_t): (minstamp, maxstamp) = stamps threshold_lo = (threshold_lo_t)[ZERO] threshold_hi = (threshold_hi_t)[ZERO] result = { 'date': ValueTuple([], 'unix_epoch', 'group_time'), 'daily_max': ValueTuple([], 'degree_C', 'group_temperature'), 'daily_min': ValueTuple([], 'degree_C', 'group_temperature'), 'dd': ValueTuple([], 'degree_C_day', 'group_degree_day'), 'dd_cumulative': ValueTuple([], 'degree_C_day', 'group_degree_day'), } try: with open(csv_file_name) as csv_file: csv_dict = csv.DictReader(csv_file) recs = [] for (ndx, rec) in enumerate(csv_dict): try: date_string = '%(YR)s/%(MO)s/%(DAY)s' % rec stamp = time.mktime( time.strptime(date_string, '%Y/%m/%d')) except ValueError: stamp = None if stamp is None: pass else: recs.append([stamp, rec]) recs.sort() dd_cumulative = ZERO for (ndx, (stamp, rec)) in enumerate(recs): if (minstamp <= stamp) and (stamp <= maxstamp): result['date'][ZERO].append(stamp) try: daily_max = float(rec.get('TMPMAX_C')) result['daily_max'][ZERO].append(daily_max) daily_min = float(rec.get('TMPMIN_C')) result['daily_min'][ZERO].append(daily_min) dd = dd_clipped(daily_max, daily_min, threshold_lo, threshold_hi) result['dd'][ZERO].append(dd) dd_cumulative += dd result['dd_cumulative'][ZERO].append(dd_cumulative) except ValueError: pass except TypeError: pass except IOError as e: log.info("Unable to read file '%s' %s:", csv_file_name, e) return result
def get_vectors(self, stamps, csv_file_name, c_temp_base_t, c4_temp_t): (minstamp, maxstamp) = stamps c_temp_base = self.to_degree_f.convert(c_temp_base_t)[ZERO] c4_temp = self.to_degree_f.convert(c4_temp_t)[ZERO] result = { 'date': ValueTuple([], 'unix_epoch', 'group_time'), 'daily_max': ValueTuple([], 'degree_F', 'group_temperature'), 'daily_min': ValueTuple([], 'degree_F', 'group_temperature'), 'dd': ValueTuple([], 'count', 'group_count'), 'dd_cumulative': ValueTuple([], 'count', 'group_count'), } try: with open(csv_file_name) as csv_file: csv_dict = csv.DictReader(csv_file) recs = [] for (ndx, rec) in enumerate(csv_dict): try: date_string = '%(YR)s/%(MO)s/%(DAY)s' % rec stamp = time.mktime( time.strptime(date_string, '%Y/%m/%d')) except ValueError: stamp = None if stamp is None: pass else: recs.append([stamp, rec]) recs.sort() dd_cumulative = ZERO for (ndx, (stamp, rec)) in enumerate(recs): if (minstamp <= stamp) and (stamp <= maxstamp): result['date'][ZERO].append(stamp) try: daily_max = float(rec.get('TMPMAX_F')) result['daily_max'][ZERO].append(daily_max) daily_min = float(rec.get('TMPMIN_F')) result['daily_min'][ZERO].append(daily_min) dd = get_growth10(daily_max, daily_min, c_temp_base, c4_temp) result['dd'][ZERO].append(dd) dd_cumulative += dd result['dd_cumulative'][ZERO].append(dd_cumulative) except ValueError: pass except TypeError: pass except IOError as e: log.critical("growth10Generator: Unable to read file '%s' %s:", csv_file_name, e) return result
def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None, **option_dict): """Get a series of an xtype, by using the main archive table. Works only for no aggregation. """ start_vec = list() stop_vec = list() data_vec = list() if aggregate_type: # This version does not know how to do aggregations, although this could be # added in the future. raise weewx.UnknownAggregation(aggregate_type) else: # No aggregation std_unit_system = None # Hit the database. for record in db_manager.genBatchRecords(*timespan): if std_unit_system: if std_unit_system != record['usUnits']: raise weewx.UnsupportedFeature( "Unit system cannot change " "within a series.") else: std_unit_system = record['usUnits'] # Given a record, use the xtypes system to calculate a value: try: value = get_scalar(obs_type, record, db_manager) data_vec.append(value[0]) except weewx.CannotCalculate: data_vec.append(None) start_vec.append(record['dateTime'] - record['interval'] * 60) stop_vec.append(record['dateTime']) unit, unit_group = weewx.units.getStandardUnitType( std_unit_system, obs_type) return (ValueTuple(start_vec, 'unix_epoch', 'group_time'), ValueTuple(stop_vec, 'unix_epoch', 'group_time'), ValueTuple(data_vec, unit, unit_group))
def test_AggregateDaily(self): """Test special aggregates that can be used against the daily summaries.""" with weewx.manager.open_manager_with_config( self.config_dict, 'wx_binding') as db_manager: month_start_tt = (2010, 3, 1, 0, 0, 0, 0, 0, -1) month_stop_tt = (2010, 4, 1, 0, 0, 0, 0, 0, -1) start_ts = time.mktime(month_start_tt) stop_ts = time.mktime(month_stop_tt) min_ge_vt = weewx.xtypes.DailySummaries.get_aggregate( 'outTemp', TimeSpan(start_ts, stop_ts), 'min_ge', db_manager, val=ValueTuple(15, 'degree_F', 'group_temperature')) self.assertEqual(min_ge_vt[0], 6) min_le_vt = weewx.xtypes.DailySummaries.get_aggregate( 'outTemp', TimeSpan(start_ts, stop_ts), 'min_le', db_manager, val=ValueTuple(0, 'degree_F', 'group_temperature')) self.assertEqual(min_le_vt[0], 2) minmax_vt = weewx.xtypes.DailySummaries.get_aggregate( 'outTemp', TimeSpan(start_ts, stop_ts), 'minmax', db_manager) self.assertAlmostEqual(minmax_vt[0], 39.28, 2) max_wind_vt = weewx.xtypes.DailySummaries.get_aggregate( 'wind', TimeSpan(start_ts, stop_ts), 'max', db_manager) self.assertAlmostEqual(max_wind_vt[0], 24.0, 2) avg_wind_vt = weewx.xtypes.DailySummaries.get_aggregate( 'wind', TimeSpan(start_ts, stop_ts), 'avg', db_manager) self.assertAlmostEqual(avg_wind_vt[0], 10.21, 2) # Double check this last one against the average calculated from the archive avg_wind_vt = weewx.xtypes.ArchiveTable.get_aggregate( 'windSpeed', TimeSpan(start_ts, stop_ts), 'avg', db_manager) self.assertAlmostEqual(avg_wind_vt[0], 10.21, 2) vecavg_wind_vt = weewx.xtypes.DailySummaries.get_aggregate( 'wind', TimeSpan(start_ts, stop_ts), 'vecavg', db_manager) self.assertAlmostEqual(vecavg_wind_vt[0], 5.14, 2) vecdir_wind_vt = weewx.xtypes.DailySummaries.get_aggregate( 'wind', TimeSpan(start_ts, stop_ts), 'vecdir', db_manager) self.assertAlmostEqual(vecdir_wind_vt[0], 88.77, 2)
def calc_windGustDir(self, key, data, db_manager): """ Set windGustDir to None if windGust is zero. Otherwise, raise weewx.NoCalculate.If""" if 'windGust' not in data \ or not self.force_null\ or data['windGust']: raise weewx.NoCalculate return ValueTuple(None, 'degree_compass', 'group_direction')
def temperature(self, input, item, event): system = event.packet['usUnits'] unit_group = weewx.units.getStandardUnitType(system, item) temp_c = self.val(input) / 1000.0 temp_v = ValueTuple(temp_c, "degree_C", "group_temperature") temp_u = weewx.units.convert(temp_v, unit_group[0]) event.packet[item] = temp_u[0]
def pressure(self, record, dbmanager): """Calculate the observation type 'pressure'.""" # All of the following keys are required: if any(key not in record for key in ['usUnits', 'outTemp', 'barometer', 'outHumidity']): raise weewx.CannotCalculate('pressure') # Get the temperature in Fahrenheit from 12 hours ago temp_12h_vt = self._get_temperature_12h(record['dateTime'], dbmanager) if temp_12h_vt is None \ or temp_12h_vt[0] is None \ or record['outTemp'] is None \ or record['barometer'] is None \ or record['outHumidity'] is None: pressure = None else: # The following requires everything to be in US Customary units. # Rather than convert the whole record, just convert what we need: record_US = weewx.units.to_US({ 'usUnits': record['usUnits'], 'outTemp': record['outTemp'], 'barometer': record['barometer'], 'outHumidity': record['outHumidity'] }) # Get the altitude in feet altitude_ft = weewx.units.convert(self.altitude_vt, "foot") # The outside temperature in F. temp_12h_F = weewx.units.convert(temp_12h_vt, "degree_F") pressure = weewx.uwxutils.uWxUtilsVP.SeaLevelToSensorPressure_12( record_US['barometer'], altitude_ft[0], record_US['outTemp'], temp_12h_F[0], record_US['outHumidity']) return ValueTuple(pressure, 'inHg', 'group_pressure')
def pressure(self, input, item, event): system = event.packet['usUnits'] unit_group = weewx.units.getStandardUnitType(system, item) pres_r = self.val(input)/10.0 pres_p = ValueTuple(pres_r, "kPa", "group_pressure") pres_u = weewx.units.convert(pres_p, unit_group[0]) event.packet[item] = pres_u[0]
def get_float_t(txt, unit_group): if txt is None: result = None elif isinstance(txt, str): if txt.lower() in [NULL, 'none']: result = None else: result = ValueTuple(float(txt[ZERO]), txt[1], unit_group) return result
def calc_windGustDir(self, key, data, db_manager): # Return the current gust direction if windGust is non-zero, otherwise, None if 'windGust' not in data: raise weewx.CannotCalculate if self.ignore_zero_wind or data['windGust']: val = data.get('windGustDir') else: val = None return ValueTuple(val, 'degree_compass', 'group_direction')
def calc_windDir(self, key, data, db_manager): # Return the current wind direction if windSpeed is non-zero, otherwise, None if 'windSpeed' not in data or 'windDir' not in data: raise weewx.CannotCalculate if self.force_null and data['windSpeed'] == 0: val = None else: val = data['windDir'] return ValueTuple(val, 'degree_compass', 'group_direction')
def __getattr__(self, obs_type): """Return the trend for the given observation type.""" # This is to get around bugs in the Python version of Cheetah's namemapper: if obs_type in ['__call__', 'has_key']: raise AttributeError db_manager = self.db_lookup(self.data_binding) # Get the current record, and one "time_delta" ago: now_record = db_manager.getRecord(self.nowtime, self.time_grace_val) then_record = db_manager.getRecord(self.nowtime - self.time_delta_val, self.time_grace_val) # Do both records exist? if now_record is None or then_record is None: # No. One is missing. trend = ValueTuple(None, None, None) else: # Both records exist. Check to see if the observation type is known if obs_type not in now_record or obs_type not in then_record: # obs_type is unknown. Signal it trend = weewx.units.UnknownType(obs_type) else: # Both records exist, both types are known. We can proceed. now_vt = weewx.units.as_value_tuple(now_record, obs_type) then_vt = weewx.units.as_value_tuple(then_record, obs_type) # Do the unit conversion now, rather than lazily. This is because the temperature # conversion functions are not distributive. That is, # F_to_C(68F - 50F) # is not equal to # F_to_C(68F) - F_to_C(50F) # We want the latter, not the former, so we perform the conversion immediately. now_vtc = self.converter.convert(now_vt) then_vtc = self.converter.convert(then_vt) if now_vtc.value is None or then_vtc.value is None: # One of the values is None, so the trend will be None. trend = ValueTuple(None, now_vtc.unit, now_vtc.group) else: # All good. Calculate the trend. trend = now_vtc - then_vtc # Return the results as a ValueHelper. Use the formatting and labeling options from the # current time record. The user can always override these. return weewx.units.ValueHelper(trend, 'current', self.formatter, self.converter)
def get_scalar(self, obs_type, record, db_manager): # We only know how to calculate 'vapor_p'. For everything else, raise an exception UnknownType if obs_type != 'vapor_p': raise weewx.UnknownType(obs_type) # We need outTemp in order to do the calculation. if 'outTemp' not in record or record['outTemp'] is None: raise weewx.CannotCalculate(obs_type) # We have everything we need. Start by forming a ValueTuple for the outside temperature. # To do this, figure out what unit and group the record is in ... unit_and_group = weewx.units.getStandardUnitType( record['usUnits'], 'outTemp') # ... then form the ValueTuple. outTemp_vt = ValueTuple(record['outTemp'], *unit_and_group) # Both algorithms need temperature in Celsius, so let's make sure our incoming temperature # is in that unit. Use function convert(). The results will be in the form of a ValueTuple outTemp_C_vt = weewx.units.convert(outTemp_vt, 'degree_C') # Get the first element of the ValueTuple. This will be in Celsius: outTemp_C = outTemp_C_vt[0] if self.algorithm == 'simple': # Use the "Simple" algorithm. # We need temperature in Kelvin. outTemp_K = weewx.units.CtoK(outTemp_C) # Now we can use the formula. Results will be in mmHg. Create a ValueTuple out of it: p_vt = ValueTuple(math.exp(20.386 - 5132.0 / outTemp_K), 'mmHg', 'group_pressure') elif self.algorithm == 'tetens': # Use Teten's algorithm. # Use the formula. Results will be in kPa: p_kPa = 0.61078 * math.exp(17.27 * outTemp_C_vt[0] / (outTemp_C_vt[0] + 237.3)) # Form a ValueTuple p_vt = ValueTuple(p_kPa, 'kPa', 'group_pressure') else: # Don't recognize the exception. Fail hard: raise ValueError(self.algorithm) # We have the vapor pressure as a ValueTuple. Convert it back to the units used by # the incoming record and return it return weewx.units.convertStd(p_vt, record['usUnits'])
def get_scalar(self, obs_type, record, db_manager): # We only know how to calculate some sun and moon related stuff. For everything else, raise an exception UnknownType if obs_type not in ('sun_altitude', 'sun_azimuth'): raise weewx.UnknownType(obs_type) # we only report sun values if the sun is above the horizon almanac = Almanac(record['dateTime'], self.lat, self.lng, 0) # TODO convert alt to meters sun_altitude = almanac.sun.alt if obs_type == 'sun_altitude': value = ValueTuple(sun_altitude if sun_altitude >= 0 else None, 'degree_compass', 'group_direction') elif obs_type == 'sun_azimuth': value = ValueTuple(almanac.sun.az if sun_altitude >= 0 else None, 'degree_compass', 'group_direction') # We have the calculated values as ValueTuples. Convert them back to the units used by # the incoming record and return it return weewx.units.convertStd(value, record['usUnits'])
def __getattr__(self, obs_type): """Return the trend for the given observation type.""" # This is to get around bugs in the Python version of Cheetah's namemapper: if obs_type in ['__call__', 'has_key']: raise AttributeError db_manager = self.db_lookup(self.data_binding) # Get the current record, and one "time_delta" ago: now_record = db_manager.getRecord(self.nowtime, self.time_grace_val) then_record = db_manager.getRecord(self.nowtime - self.time_delta_val, self.time_grace_val) # Do both records exist? if now_record is None or then_record is None: # No. One is missing. trend = ValueTuple(None, None, None) else: # Both records exist. # Check to see if the observation type is known if obs_type not in now_record or obs_type not in then_record: # obs_type is unknown. Signal it trend = weewx.units.UnknownType(obs_type) else: now_vt = weewx.units.as_value_tuple(now_record, obs_type) then_vt = weewx.units.as_value_tuple(then_record, obs_type) # Do the unit conversion now, rather than lazily. This is because, # in the case of temperature, the difference between two converted # values is not the same as the conversion of the difference # between two values. E.g., 20C - 10C is not equal to # F_to_C(68F - 50F). We want the former, not the latter. now_vtc = self.converter.convert(now_vt) then_vtc = self.converter.convert(then_vt) if now_vtc.value is None or then_vtc.value is None: trend = ValueTuple(None, now_vtc.unit, now_vtc.group) else: trend = now_vtc - then_vtc # Return the results as a ValueHelper. Use the formatting and labeling # options from the current time record. The user can always override # these. return weewx.units.ValueHelper(trend, 'current', self.formatter, self.converter)
def calc_beaufort(key, data, db_manager=None): global first_time if first_time: print("Type beaufort has been deprecated. Use unit beaufort instead.") log.info("Type beaufort has been deprecated. Use unit beaufort instead.") first_time = False if 'windSpeed' not in data: raise weewx.CannotCalculate windspeed_vt = weewx.units.as_value_tuple(data, 'windSpeed') windspeed_kn = weewx.units.convert(windspeed_vt, 'knot')[0] return ValueTuple(weewx.wxformulas.beaufort(windspeed_kn), None, None)
def get_scalar(self, obs_type, record, db_manager): # We only know how to calculate 'makkink'. For everything else, raise an exception UnknownType if obs_type != 'makkink': raise weewx.UnknownType(obs_type) # We need outTemp and the radiation in order to do the calculation. if 'outTemp' not in record or record['outTemp'] is None: raise weewx.CannotCalculate(obs_type) if 'radiation' not in record or record['radiation'] is None: raise weewx.CannotCalculate(obs_type) # We have everything we need. Start by forming a ValueTuple for the outside temperature. # To do this, figure out what unit and group the record is in ... unit_and_group = weewx.units.getStandardUnitType( record['usUnits'], 'outTemp') # ... then form the ValueTuple. outTemp_vt = ValueTuple(record['outTemp'], *unit_and_group) # same for radiation unit_and_group = weewx.units.getStandardUnitType( record['usUnits'], 'radiation') # ... then form the ValueTuple. radiation_vt = ValueTuple(record['radiation'], *unit_and_group) outTemp_C_vt = weewx.units.convert(outTemp_vt, 'degree_C') # Get the first element of the ValueTuple. This will be in Celsius: T = outTemp_C_vt[0] # just to make sure nothing fancy happens we do this for radiation as well # even though this is W/m2 in us as well as metric radiation_Wm2_vt = weewx.units.convert(radiation_vt, 'watt_per_meter_squared') Kin = radiation_Wm2_vt[0] makkink = ValueTuple( self.Eref(T, Kin) * 3600, 'mm_per_hour', 'group_rainrate') # convert from kg/m2*s --> mm/hour # Convert it back to the units used by # the incoming record and return it return weewx.units.convertStd(makkink, record['usUnits'])
def calc_humidex(key, data, db_manager=None): if 'outTemp' not in data or 'outHumidity' not in data: raise weewx.CannotCalculate(key) if data['usUnits'] == weewx.US: val = weewx.wxformulas.humidexF(data['outTemp'], data['outHumidity']) u = 'degree_F' else: val = weewx.wxformulas.humidexC(data['outTemp'], data['outHumidity']) u = 'degree_C' return ValueTuple(val, u, 'group_temperature')
def calc_maxSolarRad(self, key, data, db_manager): altitude_m = weewx.units.convert(self.altitude_vt, 'meter')[0] if self.maxSolarRad_algo == 'bras': val = weewx.wxformulas.solar_rad_Bras(self.latitude_f, self.longitude_f, altitude_m, data['dateTime'], self.nfac) elif self.maxSolarRad_algo == 'rs': val = weewx.wxformulas.solar_rad_RS(self.latitude_f, self.longitude_f, altitude_m, data['dateTime'], self.atc) else: raise weewx.ViolatedPrecondition("Unknown solar algorithm '%s'" % self.maxSolarRad_algo) return ValueTuple(val, 'watt_per_meter_squared', 'group_radiation')
def calc_inDewpoint(key, data, db_manager=None): if 'inTemp' not in data or 'inHumidity' not in data: raise weewx.CannotCalculate(key) if data['usUnits'] == weewx.US: val = weewx.wxformulas.dewpointF(data['inTemp'], data['inHumidity']) u = 'degree_F' else: val = weewx.wxformulas.dewpointC(data['inTemp'], data['inHumidity']) u = 'degree_C' return ValueTuple(val, u, 'group_temperature')
def get_extension_list(self, timespan, db_lookup): """ Returns various tags. Returns: Easter: A ValueHelper containing the date of the next Easter Sunday. The time represented is midnight at the start of Easter Sunday. """ # # Easter. Calculate date for Easter Sunday this year # def calc_easter(year): """Calculate Easter date. Uses a modified version of Butcher's Algorithm. Refer New Scientist, 30 March 1961 pp 828-829 https://books.google.co.uk/books?id=zfzhCoOHurwC&printsec=frontcover&source=gbs_ge_summary_r&cad=0#v=onepage&q&f=false """ a = year % 19 b = year // 100 c = year % 100 d = b // 4 e = b % 4 g = (8 * b + 13) // 25 h = (19 * a + b - d - g + 15) % 30 i = c // 4 k = c % 4 l = (2 * e + 2 * i - h - k + 32) % 7 m = (a + 11 * h + 19 * l) // 433 n = (h + l - 7 * m + 90) // 25 p = (h + l - 7 * m + 33 * n + 19) % 32 _dt = datetime.datetime(year=year, month=n, day=p) _ts = time.mktime(_dt.timetuple()) return _ts _year = date.today().year easter_ts = calc_easter(_year) # check to see if we have past this calculated date, if so we want next # years date so increment year and recalculate if date.fromtimestamp(easter_ts) < date.today(): easter_ts = calc_easter(_year + 1) easter_vt = ValueTuple(easter_ts, 'unix_epoch', 'group_time') easter_vh = ValueHelper(easter_vt, formatter=self.generator.formatter, converter=self.generator.converter) # Create a small dictionary with the tag names (keys) we want to use search_list_extension = { 'Easter': easter_vh, } return [search_list_extension]
def time_at(expression): """When an sql expression evaluated true""" db_manager = db_lookup() sql_stmt = "SELECT dateTime FROM %s WHERE %s AND dateTime <= %d ORDER BY dateTime DESC LIMIT 1" \ % (db_manager.table_name, expression, timespan.stop) row = db_manager.getSql(sql_stmt) val = row[0] if row else None vt = ValueTuple(val, 'unix_epoch', 'group_time') vh = ValueHelper(vt, formatter=self.generator.formatter, converter=self.generator.converter) return vh
def calc_cloudbase(self, key, data, db_manager): if 'outTemp' not in data or 'outHumidity' not in data: raise weewx.CannotCalculate(key) # Convert altitude to the same unit system as the incoming record altitude = weewx.units.convertStd(self.altitude_vt, data['usUnits']) # Use the appropriate formula if data['usUnits'] == weewx.US: formula = weewx.wxformulas.cloudbase_US u = 'foot' else: formula = weewx.wxformulas.cloudbase_Metric u = 'meter' val = formula(data['outTemp'], data['outHumidity'], altitude[0]) return ValueTuple(val, u, 'group_altitude')
def time_since(expression): """Time since a sql expression evaluted true""" db_manager = db_lookup() sql_stmt = "SELECT dateTime FROM %s WHERE %s AND dateTime <= %d ORDER BY dateTime DESC LIMIT 1" \ % (db_manager.table_name, expression, timespan.stop) row = db_manager.getSql(sql_stmt) val = timespan.stop - row[0] if row else None vt = ValueTuple(val, 'second', 'group_deltatime') vh = ValueHelper(vt, context="long_delta", formatter=self.generator.formatter, converter=self.generator.converter) return vh
def zip_vectors(self): size = len(self.vectors['date'][ZERO]) result = [] while size: result.append({}) size -= 1 for key in [ 'date', 'daily_max', 'daily_min', 'dd', 'dd_cumulative', ]: (vals, units, unit_group) = self.vectors[key] for (ndx, val) in enumerate(vals): val_t = ValueTuple(val, units, unit_group) result[ndx][key] = weewx.units.ValueHelper( val_t, 'day', self.formatter, self.converter) horizon_labels = [(cumulative_dd, horizon_label) for ((cumulative_dd, dd_units, dd_group), horizon_label) in self.plot.horizons] horizon_labels.sort() for rec in result: remarks = [] while horizon_labels: (horizon_dd, horizon_event) = horizon_labels[ZERO] cydia_a = rec['dd_cumulative'].raw if cydia_a > horizon_dd: remarks.append(horizon_event) horizon_labels.pop(ZERO) else: break val_t = ValueTuple('; '.join(remarks), None, None) rec['remark'] = weewx.units.ValueHelper(val_t, 'day', self.formatter, self.converter) return result
def get_scalar(self, key, record, db_manager): """Calculate the rainRate""" if key != 'rainRate': raise weewx.UnknownType(key) if self.rain_events is None: self._setup(record['dateTime'], db_manager) # Sum the rain events within the time window... rainsum = sum(x[1] for x in self.rain_events if x[0] > record['dateTime'] - self.rain_period) # ...then divide by the period and scale to an hour val = 3600 * rainsum / self.rain_period u, g = weewx.units.getStandardUnitType(record['usUnits'], 'rainRate') return ValueTuple(val, u, g)
def testVT(self): a=ValueTuple(68.0, "degree_F", "group_temperature") b=ValueTuple(18.0, "degree_F", "group_temperature") c=ValueTuple(None, "degree_F", "group_temperature") d=ValueTuple(1020.0, "mbar", "group_pressure") self.assertEqual(a + b, ValueTuple(86.0, "degree_F", "group_temperature")) self.assertEqual(a - b, ValueTuple(50.0, "degree_F", "group_temperature")) self.assertRaises(TypeError, operator.add, a, c) self.assertRaises(TypeError, operator.add, a, d)