def __init__(self, params, status, raw_data): self.logger = logging.getLogger('pywws.DataLogger') self.params = params self.status = status self.raw_data = raw_data # connect to weather station ws_type = self.params.get('fixed', 'ws type') if ws_type: self.params.unset('fixed', 'ws type') self.params.set('config', 'ws type', ws_type) ws_type = self.params.get('config', 'ws type', 'Unknown') avoid = eval(self.params.get('config', 'usb activity margin', '3.0')) self.ws = WeatherStation.weather_station( ws_type=ws_type, params=self.params, status=self.status, avoid=avoid) # check for valid weather station type fixed_block = self.check_fixed_block() if ws_type not in ('1080', '3080'): print "Unknown weather station type. Please edit weather.ini" print "and set 'ws type' to '1080' or '3080', as appropriate." if fixed_block['lux_wm2_coeff'] == 0.0: print "Your station is probably a '1080' type." else: print "Your station is probably a '3080' type." sys.exit(1) # check computer clock isn't earlier than last stored data last_stored = self.raw_data.before(datetime.max) if last_stored and datetime.utcnow() < last_stored: raise ValueError('Computer time is earlier than last stored data')
def WeatherStation_init(): """ create kumunication Object für WeatherStation.""" try: ws = WeatherStation.weather_station() except: raise NameError("WS conection error") return (ws)
def run(self, generate_event, send_event, context={}): from pywws import WeatherStation station = WeatherStation.weather_station() for data, last_ptr, logged in station.live_data(): if not logged: try: if data['abs_pressure'] is not None: e = generate_event('press') e.value = (10 * (4.5 + (data['abs_pressure']))) / 10 send_event(e) if data['temp_in'] is not None: e = generate_event('temp') e.sensor = 0 e.value = data['temp_in'] send_event(e) if data['hum_in'] is not None: e = generate_event('hum') e.sensor = 0 e.value = data['hum_in'] send_event(e) if data['temp_out'] is not None: e = generate_event('temp') e.sensor = 1 e.value = data['temp_out'] send_event(e) if data['hum_out'] is not None: e = generate_event('hum') e.sensor = 1 e.value = data['hum_out'] send_event(e) if data['rain'] is not None: e = generate_event('rain') e.total = (136 * (data['rain'])) / 100 e.rate = 0 send_event(e) if data['wind_ave'] is not None and data['wind_dir'] < 16: e = generate_event('wind') e.create_child('mean') e.mean.speed = data['wind_ave'] e.mean.dir = 22.5 * (data['wind_dir']) if data['wind_gust']: e.create_child('gust') e.gust.speed = data['wind_gust'] e.gust.dir = 22.5 * (data['wind_dir']) send_event(e) except Exception, e: self.logger.error(e)
def run(self, generate_event, send_event, context={}): from pywws import WeatherStation station = WeatherStation.weather_station() for data, last_ptr, logged in station.live_data(): if not logged: try: if data['abs_pressure'] is not None: e = generate_event('press') e.value = (10*(4.5+(data['abs_pressure'])))/10 send_event(e) if data['temp_in'] is not None: e = generate_event('temp') e.sensor = 0 e.value = data['temp_in'] send_event(e) if data['hum_in'] is not None: e = generate_event('hum') e.sensor = 0 e.value = data['hum_in'] send_event(e) if data['temp_out'] is not None: e = generate_event('temp') e.sensor = 1 e.value = data['temp_out'] send_event(e) if data['hum_out'] is not None: e = generate_event('hum') e.sensor = 1 e.value = data['hum_out'] send_event(e) if data['rain'] is not None: e = generate_event('rain') e.total = (136*(data['rain']))/100 e.rate = 0 send_event(e) if data['wind_ave'] is not None and data['wind_dir'] < 16: e = generate_event('wind') e.create_child('mean') e.mean.speed = data['wind_ave'] e.mean.dir = 22.5*(data['wind_dir']) if data['wind_gust']: e.create_child('gust') e.gust.speed = data['wind_gust'] e.gust.dir = 22.5*(data['wind_dir']) send_event(e) except Exception, e: self.logger.error(e)
# check arguments if len(args) != 0: print >>sys.stderr, 'Error: no arguments allowed\n' print >>sys.stderr, __usage__.strip() return 2 # process options verbose = 0 for o, a in opts: if o in ('-h', '--help'): print __usage__.strip() return 0 elif o in ('-v', '--verbose'): verbose += 1 # do it! logger = ApplicationLogger(verbose) ws = WeatherStation.weather_station() fixed_block = ws.get_fixed_block() if not fixed_block: print "No valid data block found" return 3 # loop ptr = ws.data_start total_count = 0 bad_count = 0 while True: if total_count % 1000 == 0: active = ws.current_pos() while True: ptr += 0x20 if ptr >= 0x10000: ptr = ws.data_start
# check arguments if len(args) != 0: print >> sys.stderr, 'Error: no arguments allowed\n' print >> sys.stderr, __usage__.strip() return 2 # process options verbose = 0 for o, a in opts: if o in ('-h', '--help'): print __usage__.strip() return 0 elif o in ('-v', '--verbose'): verbose += 1 # do it! logger = ApplicationLogger(verbose) ws = WeatherStation.weather_station() fixed_block = ws.get_fixed_block() if not fixed_block: print "No valid data block found" return 3 # loop ptr = ws.data_start total_count = 0 bad_count = 0 while True: if total_count % 1000 == 0: active = ws.current_pos() while True: ptr += 0x20 if ptr >= 0x10000: ptr = ws.data_start
def LogData(params, status, raw_data, sync=None, clear=False): logger = logging.getLogger('pywws.LogData') # connect to weather station ws_type = params.get('fixed', 'ws type') if ws_type: params.unset('fixed', 'ws type') params.set('config', 'ws type', ws_type) ws_type = params.get('config', 'ws type', 'Unknown') ws = WeatherStation.weather_station( ws_type=ws_type, params=params, status=status) fixed_block = CheckFixedBlock(ws, params, status, logger) if not fixed_block: logger.error("Invalid data from weather station") return 3 # check for valid weather station type if ws.ws_type not in ('1080', '3080'): print "Unknown weather station type. Please edit weather.ini" print "and set 'ws type' to '1080' or '3080', as appropriate." if fixed_block['lux_wm2_coeff'] == 0.0: print "Your station is probably a '1080' type." else: print "Your station is probably a '3080' type." sys.exit(1) # get sync config value if sync is None: if fixed_block['read_period'] <= 5: sync = int(params.get('config', 'logdata sync', '1')) else: sync = int(params.get('config', 'logdata sync', '0')) # get address and date-time of last complete logged data logger.info('Synchronising to weather station') range_hi = datetime.max range_lo = datetime.min last_delay = ws.get_data(ws.current_pos())['delay'] if last_delay == 0: prev_date = datetime.min else: prev_date = datetime.utcnow() for data, last_ptr, logged in ws.live_data(logged_only=(sync > 1)): last_date = data['idx'] logger.debug('Reading time %s', last_date.strftime('%H:%M:%S')) if logged: break if sync < 2 and ws._station_clock: err = last_date - datetime.fromtimestamp(ws._station_clock) last_date -= timedelta( minutes=data['delay'], seconds=err.seconds % 60) logger.debug('log time %s', last_date.strftime('%H:%M:%S')) last_ptr = ws.dec_ptr(last_ptr) break if sync < 1: hi = last_date - timedelta(minutes=data['delay']) if last_date - prev_date > timedelta(seconds=50): lo = hi - timedelta(seconds=60) elif data['delay'] == last_delay: lo = hi - timedelta(seconds=60) hi = hi - timedelta(seconds=48) else: lo = hi - timedelta(seconds=48) last_delay = data['delay'] prev_date = last_date range_hi = min(range_hi, hi) range_lo = max(range_lo, lo) err = (range_hi - range_lo) / 2 last_date = range_lo + err logger.debug('est log time %s +- %ds (%s..%s)', last_date.strftime('%H:%M:%S'), err.seconds, lo.strftime('%H:%M:%S'), hi.strftime('%H:%M:%S')) if err < timedelta(seconds=15): last_ptr = ws.dec_ptr(last_ptr) break # go back through stored data, until we catch up with what we've already got logger.info('Fetching data') Catchup(ws, logger, raw_data, last_date, last_ptr) if clear: logger.info('Clearing weather station memory') ptr = ws.fixed_format['data_count'][0] ws.write_data([(ptr, 1), (ptr+1, 0)])
def process(self, live_data, template_file): def jump(idx, count): while count > 0: new_idx = data_set.after(idx + SECOND) if new_idx == None: break idx = new_idx count -= 1 while count < 0: new_idx = data_set.before(idx) if new_idx == None: break idx = new_idx count += 1 return idx, count == 0 params = self.params if not live_data: idx = self.calib_data.before(datetime.max) if not idx: self.logger.error("No calib data - run Process.py first") return live_data = self.calib_data[idx] pressure_trend_text = WeatherStation.pressure_trend_text wind_dir_text = WeatherStation.get_wind_dir_text() dew_point = WeatherStation.dew_point wind_chill = WeatherStation.wind_chill apparent_temp = WeatherStation.apparent_temp rain_hour = self._rain_hour rain_day = self._rain_day pressure_offset = eval(self.params.get('fixed', 'pressure offset')) fixed_block = eval(self.params.get('fixed', 'fixed block')) # start off with no time rounding round_time = None # start off in hourly data mode data_set = self.hourly_data # start off in utc time_zone = utc # jump to last item idx, valid_data = jump(datetime.max, -1) if not valid_data: self.logger.error("No summary data - run Process.py first") return data = data_set[idx] # open template file file if sys.version_info[0] >= 3: tmplt = open(template_file, 'r', encoding=self.encoding) else: tmplt = open(template_file, 'r') # do the text processing while True: line = tmplt.readline() if line == '': break parts = line.split('#') for i in range(len(parts)): if i % 2 == 0: # not a processing directive if i == 0 or parts[i] != '\n': yield parts[i] continue if parts[i] and parts[i][0] == '!': # comment continue command = shlex.split(parts[i]) if command == []: # empty command == print a single '#' yield '#' elif command[0] in data.keys() + ['calc']: # output a value if not valid_data: continue # format is: key fmt_string no_value_string conversion # get value if command[0] == 'calc': x = eval(command[1]) del command[1] else: x = data[command[0]] # adjust time if isinstance(x, datetime): if round_time: x += round_time x = x.replace(tzinfo=utc) x = x.astimezone(time_zone) # convert data if x != None and len(command) > 3: x = eval(command[3]) # get format fmt = '%s' if len(command) > 1: fmt = command[1] # write output if x == None: if len(command) > 2: yield command[2] elif isinstance(x, datetime): yield x.strftime(fmt) elif not self.use_locale: yield fmt % (x) elif sys.version_info >= (2, 7) or '%%' not in fmt: yield locale.format_string(fmt, x) else: yield locale.format_string( fmt.replace('%%', '##'), x).replace('##', '%') elif command[0] == 'monthly': data_set = self.monthly_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'daily': data_set = self.daily_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'hourly': data_set = self.hourly_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'raw': data_set = self.calib_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'live': data_set = self.calib_data idx = datetime.max valid_data = True data = live_data elif command[0] == 'timezone': if command[1] == 'utc': time_zone = utc elif command[1] == 'local': time_zone = Local else: self.logger.error("Unknown time zone: %s", command[1]) return elif command[0] == 'roundtime': if eval(command[1]): round_time = timedelta(seconds=30) else: round_time = None elif command[0] == 'jump': prevdata = data idx, valid_data = jump(idx, int(command[1])) data = data_set[idx] elif command[0] == 'goto': prevdata = data time_str = command[1] if '%' in time_str: lcl = idx.replace(tzinfo=utc).astimezone(time_zone) time_str = lcl.strftime(time_str) new_idx = DataStore.safestrptime(time_str) new_idx = new_idx.replace(tzinfo=time_zone).astimezone(utc) new_idx = data_set.after(new_idx.replace(tzinfo=None)) if new_idx: idx = new_idx data = data_set[idx] valid_data = True else: valid_data = False elif command[0] == 'loop': loop_count = int(command[1]) loop_start = tmplt.tell() elif command[0] == 'endloop': loop_count -= 1 if valid_data and loop_count > 0: tmplt.seek(loop_start, 0) else: self.logger.error( "Unknown processing directive: #%s#", parts[i]) return tmplt.close() return
def LiveLog(data_dir): logger = logging.getLogger('pywws.LiveLog') params = DataStore.params(data_dir) status = DataStore.status(data_dir) # localise application Localisation.SetApplicationLanguage(params) # connect to weather station ws_type = params.get('fixed', 'ws type') if ws_type: params.unset('fixed', 'ws type') params.set('config', 'ws type', ws_type) ws_type = params.get('config', 'ws type', '1080') ws = WeatherStation.weather_station( ws_type=ws_type, params=params, status=status) fixed_block = CheckFixedBlock(ws, params, status, logger) if not fixed_block: logger.error("Invalid data from weather station") return 3 # open data file stores raw_data = DataStore.data_store(data_dir) calib_data = DataStore.calib_store(data_dir) hourly_data = DataStore.hourly_store(data_dir) daily_data = DataStore.daily_store(data_dir) monthly_data = DataStore.monthly_store(data_dir) # create a RegularTasks object tasks = Tasks.RegularTasks( params, status, calib_data, hourly_data, daily_data, monthly_data) # get time of last logged data two_minutes = timedelta(minutes=2) last_stored = raw_data.before(datetime.max) if last_stored == None: last_stored = datetime.min if datetime.utcnow() < last_stored: raise ValueError('Computer time is earlier than last stored data') last_stored += two_minutes # get live data hour = timedelta(hours=1) next_hour = datetime.utcnow().replace( minute=0, second=0, microsecond=0) + hour next_ptr = None for data, ptr, logged in ws.live_data( logged_only=(not tasks.has_live_tasks())): now = data['idx'] if logged: if ptr == next_ptr: # data is contiguous with last logged value raw_data[now] = data else: # catch up missing data Catchup(ws, logger, raw_data, now, ptr) next_ptr = ws.inc_ptr(ptr) # process new data Process.Process(params, status, raw_data, calib_data, hourly_data, daily_data, monthly_data) # do tasks tasks.do_tasks() if now >= next_hour: next_hour += hour fixed_block = CheckFixedBlock(ws, params, status, logger) if not fixed_block: logger.error("Invalid data from weather station") return 3 # save any unsaved data raw_data.flush() else: tasks.do_live(data) return 0
def LiveLog(data_dir): logger = logging.getLogger('pywws.LiveLog') params = DataStore.params(data_dir) # localise application Localisation.SetApplicationLanguage(params) # connect to weather station ws_type = params.get('config', 'ws type') if ws_type: params._config.remove_option('config', 'ws type') params.set('fixed', 'ws type', ws_type) ws_type = params.get('fixed', 'ws type', '1080') ws = WeatherStation.weather_station(ws_type=ws_type) fixed_block = CheckFixedBlock(ws, params, logger) if not fixed_block: logger.error("Invalid data from weather station") return 3 # open data file stores raw_data = DataStore.data_store(data_dir) calib_data = DataStore.calib_store(data_dir) hourly_data = DataStore.hourly_store(data_dir) daily_data = DataStore.daily_store(data_dir) monthly_data = DataStore.monthly_store(data_dir) # create a RegularTasks object tasks = Tasks.RegularTasks( params, calib_data, hourly_data, daily_data, monthly_data) # get time of last logged data two_minutes = timedelta(minutes=2) last_stored = raw_data.before(datetime.max) if last_stored == None: last_stored = datetime.min if datetime.utcnow() < last_stored: raise ValueError('Computer time is earlier than last stored data') last_stored += two_minutes # get live data hour = timedelta(hours=1) next_hour = datetime.utcnow().replace( minute=0, second=0, microsecond=0) + hour next_ptr = None for data, ptr, logged in ws.live_data( logged_only=(not tasks.has_live_tasks())): now = data['idx'] if logged: if ptr == next_ptr: # data is contiguous with last logged value raw_data[now] = data else: # catch up missing data Catchup(ws, logger, raw_data, now, ptr) next_ptr = ws.inc_ptr(ptr) # process new data Process.Process(params, raw_data, calib_data, hourly_data, daily_data, monthly_data) # do tasks tasks.do_tasks() if now >= next_hour: next_hour += hour fixed_block = CheckFixedBlock(ws, params, logger) if not fixed_block: logger.error("Invalid data from weather station") return 3 params.flush() else: tasks.do_live(data) return 0
def process(self, live_data, template_file): def jump(idx, count): while count > 0: new_idx = data_set.after(idx + SECOND) if new_idx == None: break idx = new_idx count -= 1 while count < 0: new_idx = data_set.before(idx) if new_idx == None: break idx = new_idx count += 1 return idx, count == 0 params = self.params if not live_data: idx = self.calib_data.before(datetime.max) if not idx: self.logger.error("No calib data - run Process.py first") return live_data = self.calib_data[idx] pressure_trend_text = WeatherStation.pressure_trend_text wind_dir_text = WeatherStation.get_wind_dir_text() dew_point = WeatherStation.dew_point wind_chill = WeatherStation.wind_chill apparent_temp = WeatherStation.apparent_temp rain_hour = self._rain_hour rain_day = self._rain_day pressure_offset = eval(self.params.get('fixed', 'pressure offset')) fixed_block = eval(self.params.get('fixed', 'fixed block')) # start off with no time rounding round_time = None # start off in hourly data mode data_set = self.hourly_data # start off in utc time_zone = utc # jump to last item idx, valid_data = jump(datetime.max, -1) if not valid_data: self.logger.error("No summary data - run Process.py first") return data = data_set[idx] # open template file file if sys.version_info[0] >= 3: tmplt = open(template_file, 'r', encoding=self.encoding) else: tmplt = open(template_file, 'r') # do the text processing while True: line = tmplt.readline() if line == '': break parts = line.split('#') for i in range(len(parts)): if i % 2 == 0: # not a processing directive if i == 0 or parts[i] != '\n': yield parts[i] continue if parts[i] and parts[i][0] == '!': # comment continue command = shlex.split(parts[i]) if command == []: # empty command == print a single '#' yield '#' elif command[0] in data.keys() + ['calc']: # output a value if not valid_data: continue # format is: key fmt_string no_value_string conversion # get value if command[0] == 'calc': x = eval(command[1]) del command[1] else: x = data[command[0]] # adjust time if isinstance(x, datetime): if round_time: x += round_time x = x.replace(tzinfo=utc) x = x.astimezone(time_zone) # convert data if x != None and len(command) > 3: x = eval(command[3]) # get format fmt = '%s' if len(command) > 1: fmt = command[1] # write output if x == None: if len(command) > 2: yield command[2] elif isinstance(x, datetime): yield x.strftime(fmt) elif not self.use_locale: yield fmt % (x) elif sys.version_info >= (2, 7) or '%%' not in fmt: yield locale.format_string(fmt, x) else: yield locale.format_string(fmt.replace('%%', '##'), x).replace('##', '%') elif command[0] == 'monthly': data_set = self.monthly_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'daily': data_set = self.daily_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'hourly': data_set = self.hourly_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'raw': data_set = self.calib_data idx, valid_data = jump(datetime.max, -1) data = data_set[idx] elif command[0] == 'live': data_set = self.calib_data idx = datetime.max valid_data = True data = live_data elif command[0] == 'timezone': if command[1] == 'utc': time_zone = utc elif command[1] == 'local': time_zone = Local else: self.logger.error("Unknown time zone: %s", command[1]) return elif command[0] == 'roundtime': if eval(command[1]): round_time = timedelta(seconds=30) else: round_time = None elif command[0] == 'jump': prevdata = data idx, valid_data = jump(idx, int(command[1])) data = data_set[idx] elif command[0] == 'goto': prevdata = data time_str = command[1] if '%' in time_str: lcl = idx.replace(tzinfo=utc).astimezone(time_zone) time_str = lcl.strftime(time_str) new_idx = DataStore.safestrptime(time_str) new_idx = new_idx.replace(tzinfo=time_zone).astimezone(utc) new_idx = data_set.after(new_idx.replace(tzinfo=None)) if new_idx: idx = new_idx data = data_set[idx] valid_data = True else: valid_data = False elif command[0] == 'loop': loop_count = int(command[1]) loop_start = tmplt.tell() elif command[0] == 'endloop': loop_count -= 1 if valid_data and loop_count > 0: tmplt.seek(loop_start, 0) else: self.logger.error("Unknown processing directive: #%s#", parts[i]) return tmplt.close() return
def main(): # read wws2mysql.ini config config = ConfigParser.ConfigParser() config.readfp(open('wws2mysql.ini')) # init slogging syslog.openlog(ident=config.get('syslog', 'ident'), logoption=syslog.LOG_PID, facility=syslog.LOG_LOCAL7) # db connection information dbcon = { 'engine': config.get('mysql_db', 'engine'), 'user': config.get('mysql_db', 'user'), 'password': config.get('mysql_db', 'password'), 'host': config.get('mysql_db', 'host'), 'database': config.get('mysql_db', 'database'), 'table': config.get('mysql_db', 'table') } print(dbcon) #tries to reconnection i = 6 conection = True #reconnect loop while (conection and (i > 0)): conection = False i -= 1 # init interface to Wetter station print("start wws connection") try: ws = WeatherStation_init() except: conection = True print("wws connection error") continue syslog.syslog(syslog.LOG_DEBUG, "connected to weather station") # init time synchronization print("synchronization of wws timing") try: last_date = WeatherStation_synctime(ws) except: conection = True print("timing error") continue syslog.syslog(syslog.LOG_DEBUG, "weather station is synchronized") # init database connection print("init database") try: sqldb = db.mysql_interface(dbcon['engine'], dbcon['user'], dbcon['password'], dbcon['host'], dbcon['database']) except: conection = True print("db conection error!") continue syslog.syslog(syslog.LOG_DEBUG, "database connection initialized") # if connection field multiple times raise error if (conection): syslog.syslog(syslog.LOG_ERR, "Connection establishment field multiple times!") raise NameError("Waring! connection field multiple times!") # read Fixblock fixb = WeatherStation_fixed_block(ws) # fined ptr position max_data = WeatherStation_ptr_pos(fixb) # read data from ring buffer # currant position in ring buffer r_pos_a = r_pos = ws.current_pos() # read last db entry last_entry = sqldb.read_last_entry(dbcon['table'], last_by='ID') # Value 5 in list is the time of the measurement. # Value delay = 5 # if db is empty use a dummy entry. if (last_entry == None): syslog.syslog(syslog.LOG_INFO, "weather station database is probably empty") last_entry = [ 0, 1, 2, 3, 4, datetime.datetime(1970, 1, 1, 0, 0, 0), 6, 7, 8, 9, 10, 360, 360 ] print(last_entry) # all data of ring buffer all_data = {} max_data = 0 #debug #r_ptss= [] # if data from wws is newer then in db start synchronization. if (verify_wws2db_timing(last_date, last_entry[5], delay - 2)): block = ws.get_data(r_pos) last_date = last_date - datetime.timedelta(minutes=block['delay'], seconds=0) last_date.replace(second=0) block['idz'] = last_date # determinant current end of ring buffer if (ws.get_data(ws.inc_ptr(r_pos), unbuffered=False)['delay'] is None): ptr_stop = 256 else: ptr_stop = ws.inc_ptr(r_pos) # read ring buffer while (r_pos_a != ptr_stop) and (last_date > last_entry[5]): #while (r_pos_a != ptr_stop) and (verify_wws2db_timing( last_date, last_entry[5], delay-2)): r_pos_a = ws.dec_ptr(r_pos_a) # debug #r_ptss.append(r_pos_a) #tray to reconnect i = 4 while (i > 0): try: block = ws.get_data(r_pos_a, unbuffered=False) except: i -= 1 print("\n USB Timed out!\n") # reconnect to wws del ws try: ws = WeatherStation.weather_station() except: print("wws connection error") syslog.syslog( syslog.LOG_ERR, "Connection field multiple times well synchronizing!" ) raise NameError( "Waring!Connection field multiple times well synchronizing!" ) print("\n reconnected!\n\n") continue break # add timestamps # ATTENTION!! Time allwaise in utc time # http://de.wikipedia.org/wiki/Koordinierte_Weltzeit last_date = last_date - datetime.timedelta(minutes=block['delay'], seconds=0) last_date.replace(second=0) block['idz'] = last_date # add pointer to list block['ptr'] = r_pos_a print block all_data[max_data] = block max_data += 1 # write data to db print("writing to DB") # daten in umgekerter reienfolge in db schreiben. damit sie cronologisch richtig sind mit der id. i = len(all_data) - 2 # maximale anzahl zu syncronisirenden daten # -1 wegen 0 zehlbeginn; -1 wegen bereitz in db vorhandenen datensatz while (i >= 0): print(i) # round long floats for k in all_data[i]: if (isinstance(all_data[i][k], float)): all_data[i][k] = round(all_data[i][k], 2) # insert in db print(all_data[i]) sqldb.insert_in_db(dbcon['table'], all_data[i]) # commuting cycle. every 10 entry auto commit. if (i % 10 == 0): sqldb.commit() i -= 1 # final commit for uncommitted enters sqldb.commit() syslog.syslog(syslog.LOG_INFO, "weather station synchronization was successful") else: print("db already actual.") syslog.syslog(syslog.LOG_INFO, "weather station db was already actual") # test output to file if (config.getboolean('file_output', 'output')): print "writing to file" write_to_file('out.txt', fixb, all_data) print "all complete" del ws del sqldb return 0
def run(self, generate_event, send_event, context={}): from pywws import WeatherStation # cyclic try connecting to weather station (when USB is disconnected) while True: try: station = WeatherStation.weather_station() for data, last_ptr, logged in station.live_data(): if not logged: try: if data['abs_pressure'] is not None: e = generate_event('press') e.value = data['abs_pressure'] send_event(e) if data['temp_in'] is not None: e = generate_event('temp') e.sensor = 0 e.value = data['temp_in'] send_event(e) if data['hum_in'] is not None: e = generate_event('hum') e.sensor = 0 e.value = data['hum_in'] send_event(e) if data['temp_out'] is not None: e = generate_event('temp') e.sensor = 1 e.value = data['temp_out'] send_event(e) if data['hum_out'] is not None: e = generate_event('hum') e.sensor = 1 e.value = data['hum_out'] send_event(e) if data['rain'] is not None: e = generate_event('rain') e.total = data['rain'] e.rate = 0 send_event(e) if data['wind_ave'] is not None and 0 <= data[ 'wind_dir'] < 16: dir_degrees = data[ 'wind_dir'] * 22.5 # 360 / 16 = 22.5 e = generate_event('wind') e.create_child('mean') e.mean.speed = data['wind_ave'] e.mean.dir = dir_degrees e.create_child('gust') if data['wind_gust'] is not None: e.gust.speed = data['wind_gust'] e.gust.dir = dir_degrees else: e.gust.speed = None e.gust.dir = None send_event(e) except Exception, e: self.logger.error(e) except IOError, e: self.logger.error('Exception IOError: ' + str(e)) finally:
def run(self, generate_event, send_event, context={}): from pywws import WeatherStation # pywws manages a wh1080 by default. Therefore '3080' shall be passed. station = WeatherStation.weather_station('3080') for data, last_ptr, logged in station.live_data(): if not logged: try: if data['abs_pressure'] is not None: e = generate_event('press') e.value = (10*(4.5+230+(data['abs_pressure'])))/10 #e.value = (10*(data['abs_pressure']))/10 send_event(e) if data['temp_in'] is not None: e = generate_event('temp') e.sensor = 0 e.value = data['temp_in'] send_event(e) if data['hum_in'] is not None: e = generate_event('hum') e.sensor = 0 e.value = data['hum_in'] send_event(e) if data['temp_out'] is not None: e = generate_event('temp') e.sensor = 1 e.value = data['temp_out'] send_event(e) if data['hum_out'] is not None: e = generate_event('hum') e.sensor = 1 e.value = data['hum_out'] send_event(e) if data['rain'] is not None: e = generate_event('rain') e.total = (136*(data['rain']))/100 e.rate = 0 send_event(e) if data['wind_ave'] is not None and data['wind_dir'] < 16: e = generate_event('wind') e.create_child('mean') e.mean.speed = data['wind_ave'] e.mean.dir = 22.5*(data['wind_dir']) e.create_child('gust') e.gust.speed = 0.0; e.gust.dir = 0.0; if data['wind_gust']: #e.create_child('gust') e.gust.speed = data['wind_gust'] e.gust.dir = 22.5*(data['wind_dir']) send_event(e) # pywws manages "uv" in the case of 3080 stations if data['uv'] is not None: e = generate_event('uv') e.sensor = 1 e.value = data['uv'] send_event(e) # pywws manages the "illuminance" in the case of 3080 stations if data['illuminance'] is not None: e = generate_event('rad') e.sensor = 1 e.value = (meteo.convert_illuminance_wm2(data['illuminance'])) send_event(e) except Exception, e: self.logger.error(e) except Exception, e: self.logger.error(e)
def main(): ws = WeatherStation.weather_station() #print ws.get_fixed_block() #Make sure you have trailing / ROOTDIR='/pub/vault/weather/' RAINDATA='RAINDATA.pickle' pressure_offset=.48 # Grab raw current output #We should see 'success' in this file if everything uploads to wunderground ok. STATUSFILE=ROOTDIR +'wgetfile.log' # Necessary Variables #============================================================ # Need to parse this data and create variables for uploading to wunderground ID='MyStationID' PASSWORD='******' THEEPOCHTIME=str(int(round(time.time(), 0))) CURRENTTIME=time.strftime("%Y-%m-%d+%T", time.gmtime()) WEBTIME=urllib.pathname2url(CURRENTTIME) #print ws.get_data(ws.current_pos(), unbuffered=False) #Create blank dictionary and then copy this from current buffer from WeatherStation. currentdata={} currentdata = ws.get_data(ws.current_pos(), unbuffered=False) #get_data gives us a dictionary back. Here are the keys to work with #'hum_out': 97, 'wind_gust': 0, 'wind_ave': 0, 'rain': 167.7, 'temp_in': 28.900000000000002, 'delay': 0, 'abs_pressure': 1008.8000000000001, 'hum_in': 37, 'temp_out': 12.200000000000001, 'wind_dir': 14 #======================================================= # UNIT CONVERSION #====================================================== #Now lets convert some of these key/value pairs to a unit that Wunderground uses. #Convert Windgust from m/s to MPH currentdata['wind_gust']=round(float(currentdata['wind_gust']) * 2.237,1) #Convert Wind Speed from m/s to MPH currentdata['wind_ave']=round(float(currentdata['wind_ave']) * 2.237, 1) #Convert from C to fahrenheit currentdata['temp_in']=round(float(currentdata['temp_in']) * 1.8 + 32, 1) currentdata['temp_out']=round(float(currentdata['temp_out']) * 1.8 + 32, 1) #Convert RAINTOTAL from mm to inches currentdata['rain']=int(currentdata['rain']) * 0.039370 #Convert barometer from hPa to inches currentdata['abs_pressure']=(float(currentdata['abs_pressure']) * 0.0295) + pressure_offset # Calculate dewpoint # Td = T - ((100 - RH)/5.) Td is dewpoint, T in celsius DEWPOINT=float(currentdata['temp_out']) - 9/25 * (100 - int(currentdata['hum_out'])) #TD: =243.04*(LN(RH/100)+((17.625*T)/(243.04+T)))/(17.625-LN(RH/100)-((17.625*T)/(243.04+T))) #Convert wind_dir integer which is 0-16 by 22.5 to give degrees. currentdata['wind_dir']=float(currentdata['wind_dir']) * 22.5 #===================================================== # Rain Calculations #==================================================== #RAIN LOGIC. Wunderground wants hourly rainfall, not total which is provided from the weather station. # We need to save the total at an hourly period, save epoch time (in seconds) and then we add up the delta for the hourly rollup. #Then at the next hour or (3600 seconds), we zero out the hourly and take another total rainfall snapshot. if os.path.exists(ROOTDIR + RAINDATA) == True: #Create dictionarys to store previous stats and unpack these via pickle file raindata={} with open(ROOTDIR+RAINDATA, "rb") as dictionaryfh: try: raindata = pickle.load(dictionaryfh) except: print "Pickle load had an exception. Going to have to go with current stats as starting point." #If the pickle file is bad, then we'll start over like the file doesn't exist raindata['HOURLYSNAPSHOT']= THEEPOCHTIME raindata['RAINHOURLY']=currentdata['rain'] raindata['MIDNIGHTSNAPSHOT']=currentdata['rain'] RAINDELTA=0 DAILYRAINTOTAL=0 dictionaryfh.close() #add rain logic here #here we'll set RAINDELTA and DAILYTOTAL values if int(THEEPOCHTIME) - int(raindata['HOURLYSNAPSHOT']) >= 3600: #We need to redo snapshot for our hourly raindata['HOURLYSNAPSHOT']= THEEPOCHTIME raindata['RAINHOURLY']=currentdata['rain'] RAINDELTA=0 else: RAINDELTA=float(currentdata['rain']) - float(raindata['RAINHOURLY']) #Check for midnight # Lets also run through a test to see if we need to update the 'dailyrain' value. # This we need to take a snapshot at midnight of total rainfall. Then we will do a delta throughout the day based on the snapshot. # The idea is, if we're running this script every minute, then we'll land at midnight (since we're not grep'ing on seconds) at least once. # If we change the script execution time, then this isn't going to work correctly. If its set under 60 seconds, then we'll just reset a few times # which should not be a BIG issue. The likely hood of the rain numbers incrementing much in a few seconds at midnight is very unlikely and # I don't think we're going for that kind of accuracy. #grab time. Then strip out the seconds. Since we're just checking to see if we're at midnight checktime=time.strftime("%T", time.localtime()).split(':') timenoseconds=checktime[0] + ':' + checktime[1] if timenoseconds == '00:00': print "Its midnight" #Starting over since its midnight raindata['MIDNIGHTSNAPSHOT'] = float(currentdata['rain']) DAILYRAINTOTAL=0 else: print "its NOT midnight" DAILYRAINTOTAL=float(currentdata['rain']) - float(raindata['MIDNIGHTSNAPSHOT']) else: print "No pickle file found. Initial run assumed." raindata={} raindata['HOURLYSNAPSHOT']= THEEPOCHTIME raindata['RAINHOURLY']=currentdata['rain'] raindata['MIDNIGHTSNAPSHOT']=currentdata['rain'] RAINDELTA=0 DAILYRAINTOTAL=0 #Lets dump our dictionary for next run with open (ROOTDIR+RAINDATA, 'wb') as dictionaryfh: pickle.dump((raindata), dictionaryfh) dictionaryfh.close() #We need to replicate this: #Maybe pycurl or urllib? #wget -O$STATUSFILE "http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=$ID&PASSWORD=$PASSWORD&dateutc=$THETIME&winddir=$WINDDIR&windspeedmph=$WINDSPEEDM&windgustmph=$WINDGUSTM&tempf=$TEMPF&rainin=$RAINDELTA&dailyrainin=$DAILYTOTAL&baromin=$BAROINCHES&dewptf=$DEWPOINTF&humidity=$OUTHUMIDITY&weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw" buf = cStringIO.StringIO() #Set various variables for URL to make it a little more manageable as a string WURL='http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?' AUTH='ID=' + ID + '&' + 'PASSWORD='******'&' THETIME='dateutc=' + WEBTIME + '&' WINDIR='winddir=' + str(currentdata['wind_dir']) + '&' WINDSPEED='windspeedmph=' + str(currentdata['wind_ave']) + '&' WINDGUST='windgustmph=' + str(currentdata['wind_gust']) + '&' TEMP='tempf=' + str(currentdata['temp_out']) + '&' RAININ='rainin=' + str(RAINDELTA) + '&' #add variable here DAILYRAIN='dailyrainin=' + str(DAILYRAINTOTAL) + '&' BARO='baromin=' + str(currentdata['abs_pressure']) + '&' DEW='dewptf=' + str(DEWPOINT) + '&' HUM='humidity=' + str(currentdata['hum_out']) + '&' TRAILER="weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw" c = pycurl.Curl() c.setopt(c.URL, WURL + AUTH + THETIME + WINDIR + WINDSPEED + WINDGUST + TEMP + RAININ + DAILYRAIN + BARO + DEW + HUM + TRAILER) c.setopt(c.WRITEFUNCTION, buf.write) c.perform() #Print output from wunderground print "Sending the following URL: " print WURL + AUTH + THETIME + WINDIR + WINDSPEED + WINDGUST + TEMP + RAININ + DAILYRAIN + BARO + DEW + HUM + TRAILER print "Returned value: ", buf.getvalue() #Print to log file with open(ROOTDIR + 'weather.log','w') as rawfile: print >> rawfile, "Sending the following URL: ", WURL + AUTH + THETIME + WINDIR + WINDSPEED + WINDGUST + TEMP + RAININ + DAILYRAIN + BARO + DEW + HUM + TRAILER, " Returned value: ", buf.getvalue() rawfile.close() buf.close()