# coding=utf-8 from datetime import datetime, timedelta import numpy from .time import hhmm_to_offset symbols = { 'TIME': {'type': numpy.int32}, 'ACCURAIN': {'type': numpy.float32}, } class LineParseError(BaseException): """Error parsing line of record data. """ @classmethod def raise_wrapped(cls, exception, msg=None): import sys traceback = sys.exc_info()[2] msg = msg or str(exception) raise cls(msg), None, traceback def parse_v0_record(line): """ Key/Value (Before June 2 2012) ============================== TIME: Seconds since Jan 1, 1970 ACCURAIN: Accumulated precipitation (mm) TEMP107_4: Auxillary temperature* LI200X: Solar Flux (w/m^2) TEMP107_1: Box temperature* RH41372: Relative humidity (%) TEMP107_5: Auxillary temperature* CS105: Box pressure* PAROSCI: Pressure (hPa) WSPD05305: Wind speed (m/s) TEMP107_3: Axullary temperature* CS10162: Box relative humidity* RAIN380M: Precipitation (0.01in) TEMP107_2: Outside box temperature* TEMP41372: Air temperature (ºC) WDIR05305: Wind direction (degrees) """ parts = line.split() if len(parts) != 32: msg = "Expected 32 line parts, got {:d}".format(len(parts)) raise LineParseError(msg) raw_data = {k: v for k, v in zip(parts[0::2], parts[1::2])} time_str = raw_data['TIME'] try: unix_time = int(time_str) except ValueError as err: msg = "Could not parse unix time from {}".format(time_str) LineParseError.raise_wrapped(err, msg) else: stamp = datetime.utcfromtimestamp(unix_time) return stamp, raw_data class RecordV1(dict): """ CSV (June 2 2012 to ...) ============================ StationId* Year Day of year HourMinute Seconds Box Presure* ParoSci Air Temperature period* ParoSci Pressure period* ParoSci Air Temperature* Pressure (hPa) ParoSci Calc. Sig.* Box relative humidity* Box air temperature* Auxillary Air Temp2* Auxillary Air Temp3* Auxillary Air Temp4* Wind Speed (m/s) Wind Direction (degrees) RH Shield Freq.* Relative Humidity (%) Air Temperature 6.3m (ºC) Dewpoint (ºC) RTD Shield Freq.* Air temperature (ºC) Solar Flux (w/m^s) Precipitation (.01in) Acumulated Precip (mm) *reset at 0z Altimeter (inHg) """ names = ['station_id', 'year', 'doy', 'hhmm', 'sec', 'box_pressure', 'paro_air_temp_period', 'paro_pressure_period', 'paro_air_temp', 'pressure', 'paro_cal_sig', 'box_rh', 'box_air_temp', 'air_temp_2', 'air_temp_3', 'air_temp_4', 'wind_speed', 'wind_dir', 'rh_shield_freq', 'rh', 'air_temp_6-3m', 'dewpoint', 'rtd_shield_freq', 'air_temp', 'solar_flux', 'precip', 'accum_precip', 'altimeter'] def __init__(self, line): super(self.__class__, self).__init__() parts = line.split(',') if len(parts) != 29: raise LineParseError("Expected 29 parts, got {:d}".format(len(parts))) self.update({k: v for k, v in zip(self.names, parts)}) def __getattr__(self, name, default=None): return self.get(name, default) def get_stamp(self): year = int(self['year']) doy = int(self['doy']) dt = datetime.strptime('{:d}.{:03d}'.format(int(year), int(doy)), '%Y.%j') secs = hhmm_to_offset(self['hhmm']) secs += float(self['sec']) secs -= (secs % 5) dt += timedelta(seconds=secs) return dt