Пример #1
0
    def _precalc(self):
        """Precalculate local variables."""
        self.moon_index, self._moon_fullness = weeutil.Moon.moon_phase_ts(
            self.time_ts)
        self.moon_phase = self.moon_phases[self.moon_index]
        self.time_djd = timestamp_to_djd(self.time_ts)

        # Check to see whether the user has module 'ephem'.
        if 'ephem' in sys.modules:

            self.hasExtras = True

        else:

            # No ephem package. Use the weeutil algorithms, which supply a minimum of functionality
            (y, m, d) = time.localtime(self.time_ts)[0:3]
            (sunrise_utc_h,
             sunset_utc_h) = weeutil.Sun.sunRiseSet(y, m, d, self.lon,
                                                    self.lat)
            sunrise_ts = weeutil.weeutil.utc_to_ts(y, m, d, sunrise_utc_h)
            sunset_ts = weeutil.weeutil.utc_to_ts(y, m, d, sunset_utc_h)
            self._sunrise = weewx.units.ValueHelper(ValueTuple(
                sunrise_ts, "unix_epoch", "group_time"),
                                                    context="ephem_day",
                                                    formatter=self.formatter,
                                                    converter=self.converter)
            self._sunset = weewx.units.ValueHelper(ValueTuple(
                sunset_ts, "unix_epoch", "group_time"),
                                                   context="ephem_day",
                                                   formatter=self.formatter,
                                                   converter=self.converter)
            self.hasExtras = False
Пример #2
0
 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',
             'daily_avg',
             '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]
             if rec['dd_cumulative'].raw > 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
Пример #3
0
    def get_series(obs_type,
                   timespan,
                   db_manager,
                   aggregate_type=None,
                   aggregate_interval=None,
                   **option_dict):
        """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))
Пример #4
0
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None):
        """Get a series, possibly with aggregation, from the main archive database.

        The general strategy is that if aggregation is asked for, chop the series up into separate chunks,
        calculating the aggregate for each chunk. Then assemble the results.

        If no aggregation is called for, just return the data directly out of the database.
        """

        startstamp, stopstamp = timespan
        start_vec = list()
        stop_vec = list()
        data_vec = list()

        if aggregate_type:
            # With aggregation
            unit, unit_group = None, None
            if aggregate_type == 'cumulative':
                total = 0
            for stamp in weeutil.weeutil.intervalgen(startstamp, stopstamp, aggregate_interval):
                agg_vt = get_aggregate(obs_type, stamp, aggregate_type, db_manager)
                if unit:
                    # It's OK if the unit is unknown (=None).
                    if agg_vt[1] is not None and (unit != agg_vt[1] or unit_group != agg_vt[2]):
                        raise weewx.UnsupportedFeature("Cannot change unit groups within an aggregation.")
                else:
                    unit, unit_group = agg_vt[1:]
                start_vec.append(stamp.start)
                stop_vec.append(stamp.stop)
                if aggregate_type == 'cumulative':
                    total += agg_vt[0]
                    data_vec.append(total)
                else:
                    data_vec.append(agg_vt[0])

        else:
            # Without aggregation. We only know how to get series that are in the database schema:
            if obs_type not in db_manager.sqlkeys:
                raise weewx.UnknownType(obs_type)

            # No aggregation
            sql_str = "SELECT dateTime, %s, usUnits, `interval` FROM %s " \
                      "WHERE dateTime >= ? AND dateTime <= ?" % (obs_type, db_manager.table_name)
            std_unit_system = None
            for record in db_manager.genSql(sql_str, (startstamp, stopstamp)):
                if std_unit_system:
                    if std_unit_system != record[2]:
                        raise weewx.UnsupportedFeature("Unit type cannot change within an aggregation interval.")
                else:
                    std_unit_system = record[2]
                start_vec.append(record[0] - record[3] * 60)
                stop_vec.append(record[0])
                data_vec.append(record[1])
            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))
Пример #5
0
    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))
Пример #6
0
    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))
Пример #7
0
    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
Пример #8
0
    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
Пример #9
0
    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))
Пример #10
0
    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)
Пример #11
0
 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')
Пример #12
0
 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]
Пример #13
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')
Пример #14
0
 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]
Пример #15
0
 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')
Пример #16
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
Пример #17
0
 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')
Пример #18
0
    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)
Пример #19
0
    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'])
Пример #20
0
    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'])
Пример #21
0
    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)
Пример #22
0
 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)
Пример #23
0
    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'])
Пример #24
0
 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')
Пример #25
0
 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')
Пример #26
0
 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')
Пример #27
0
    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]
Пример #28
0
        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
Пример #29
0
        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
Пример #30
0
 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')