def LogData(params, raw_data, sync=None, clear=False): logger = logging.getLogger('pywws.LogData') # connect to weather station ws_type = params.get('config', 'ws type', '1080') 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 # get sync config value if sync is None: sync = int(params.get('config', 'logdata sync', '1')) # get address and date-time of last complete logged data logger.info('Synchronising to weather station') for data, last_ptr, logged in ws.live_data(logged_only=(sync > 0)): last_date = data['idx'] logger.debug('Reading time %s', last_date.strftime('%H:%M:%S')) if logged: break if sync < 1 and last_date.second > 5 and last_date.second < 55: last_date = last_date.replace(second=0) - timedelta(minutes=data['delay']) 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 GetData(self): while 1: try: for data, ptr, ret in self.live_data(): if ret : globalvars.meteo_data.status = data[ "status"] if globalvars.meteo_data.status == 0: globalvars.meteo_data.last_measure_time = datetime.datetime.now() globalvars.meteo_data.wind_dir = data["wind_dir"] globalvars.meteo_data.idx = data[ "idx"] globalvars.meteo_data.hum_out = data["hum_out"] globalvars.meteo_data.wind_gust = (float(data["wind_gust"])*3.6)*self.cfg.windspeed_gain + self.cfg.windspeed_offset globalvars.meteo_data.wind_ave = (float(data["wind_ave"])*3.6)*self.cfg.windspeed_gain + self.cfg.windspeed_offset globalvars.meteo_data.rain = float(data["rain"]) globalvars.meteo_data.temp_in = float(data["temp_in"]) globalvars.meteo_data.delay = float(data["delay"]) globalvars.meteo_data.abs_pressure = float(data["abs_pressure"]) globalvars.meteo_data.hum_in = float(data["hum_in"]) globalvars.meteo_data.temp_out = float(data["temp_out"]) wind_dir = data[ "wind_dir"] if ( wind_dir < 16 ): globalvars.meteo_data.wind_dir = wind_dir * 22.5 globalvars.meteo_data.wind_dir_code = WeatherStation.get_wind_dir_text()[wind_dir] else: globalvars.meteo_data.wind_dir_code = None globalvars.meteo_data.wind_dir_code = None globalvars.meteo_data.illuminance = None globalvars.meteo_data.uv = None # TO REMOVE if ( globalvars.meteo_data.abs_pressure == 0 ) : globalvars.meteo_data.abs_pressure = None if ( self.cfg.use_bmp085 ): sensor.Sensor.ReadBMP085_temp_in(self) globalvars.meteo_data.CalcStatistics() globalvars.meteo_data.LogDataToDB() else: log("Meteo : Error in getting data - status = " + str(globalvars.meteo_data.status)) self.error = False except IOError,e: #raise log("ERROR with PCE-FWS20 %s . Will retry ..." % e) # ret,self.model,self.idd,self.bus = self.Detect() # usbdevice = "/dev/bus/usb/%s/%s" % (self.idd , self.bus ) # os.system( "./usbreset %s" % (usbdevice) ) self.__init__(self.cfg) self.error = True
def SetTimeFromWeatherStation(self): log("Trying to get time from WH1080. Please wait ...") try: read_period = self.ws.get_fixed_block(['read_period'], True) if (read_period != 1): self.ws._write_byte(self.ws.fixed_format['read_period'][0], 1) self.ws._write_byte(self.ws.fixed_format['data_changed'][0], 0xAA) # wait for station to clear 'data changed' while True: ack = WeatherStation._decode( self.ws._read_fixed_block(0x0020), self.ws.fixed_format['data_changed']) if ack == 0: break log('Write_data waiting for ack') time.sleep(6) except: pass oldpos = None while (oldpos == None): try: oldpos = self.ws.current_pos() except: log("Error getting station pointer .. retrying") time.sleep(1) oldpos = None found = False while (not found): try: time.sleep(2) newpos = self.ws.current_pos() if (newpos != oldpos): found = True except: pass thetime = None while (thetime == None): try: thetime = self.ws.get_fixed_block(['date_time'], True) except: log("Error getting station time .. retrying") time.sleep(1) thetime = None #print thetime os.system("sudo date -s '%s'" % thetime) log("System time adjusted from WH1080")
def SetTimeFromWeatherStation(self): log("Trying to get time from WH1080. Please wait ...") try: read_period = self.ws.get_fixed_block(['read_period'],True) if ( read_period != 1) : self.ws._write_byte(self.ws.fixed_format['read_period'][0],1) self.ws._write_byte(self.ws.fixed_format['data_changed'][0], 0xAA) # wait for station to clear 'data changed' while True: ack = WeatherStation._decode( self.ws._read_fixed_block(0x0020), self.ws.fixed_format['data_changed']) if ack == 0: break log('Write_data waiting for ack') time.sleep(6) except: pass oldpos = None while (oldpos==None) : try: oldpos = self.ws.current_pos() except: log("Error getting station pointer .. retrying") time.sleep(1) oldpos = None found = False while ( not found ): try: time.sleep(2) newpos = self.ws.current_pos() if ( newpos != oldpos): found = True except: pass thetime = None while ( thetime == None): try: thetime = self.ws.get_fixed_block(['date_time'],True) except: log("Error getting station time .. retrying") time.sleep(1) thetime = None #print thetime os.system("sudo date -s '%s'" % thetime) log("System time adjusted from WH1080")
def __init__(self,cfg ): self.error = False sensor.Sensor.__init__(self,cfg ) ret,self.model,self.idd,self.bus = self.Detect() if ( not ret ): log("ERROR - No PCE-FWS20 station found. ") os.system("sudo ./killswpi.sh") else: log("Detected : %s" % self.model) try: self.ws = WeatherStation.weather_station() except IOError,e: log("Error initializining ws")
def __init__(self, cfg): self.error = False sensor.Sensor.__init__(self, cfg) ret, self.model, self.idd, self.bus = self.Detect() if (not ret): log("ERROR - No PCE-FWS20 station found. ") os.system("sudo ./killswpi.sh") else: log("Detected : %s" % self.model) try: self.ws = WeatherStation.weather_station() except IOError, e: log("Error initializining ws")
def LogData(params, raw_data, sync=None, clear=False): logger = logging.getLogger('pywws.LogData') # 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', 'Unknown') ws = WeatherStation.weather_station(ws_type=ws_type, params=params) fixed_block = CheckFixedBlock(ws, params, 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 GetData(self): while 1: try: for data, ptr, ret in self.live_data(): if ret: globalvars.meteo_data.status = data["status"] if globalvars.meteo_data.status == 0: globalvars.meteo_data.last_measure_time = datetime.datetime.now( ) globalvars.meteo_data.wind_dir = data["wind_dir"] globalvars.meteo_data.idx = data["idx"] globalvars.meteo_data.hum_out = data["hum_out"] globalvars.meteo_data.wind_gust = ( float(data["wind_gust"]) * 3.6 ) * self.cfg.windspeed_gain + self.cfg.windspeed_offset globalvars.meteo_data.wind_ave = ( float(data["wind_ave"]) * 3.6 ) * self.cfg.windspeed_gain + self.cfg.windspeed_offset globalvars.meteo_data.rain = float(data["rain"]) globalvars.meteo_data.temp_in = float( data["temp_in"]) globalvars.meteo_data.delay = float(data["delay"]) globalvars.meteo_data.abs_pressure = float( data["abs_pressure"]) globalvars.meteo_data.hum_in = float( data["hum_in"]) globalvars.meteo_data.temp_out = float( data["temp_out"]) wind_dir = data["wind_dir"] if (wind_dir < 16): globalvars.meteo_data.wind_dir = wind_dir * 22.5 globalvars.meteo_data.wind_dir_code = WeatherStation.get_wind_dir_text( )[wind_dir] else: globalvars.meteo_data.wind_dir_code = None globalvars.meteo_data.wind_dir_code = None globalvars.meteo_data.illuminance = None globalvars.meteo_data.uv = None # TO REMOVE if (globalvars.meteo_data.abs_pressure == 0): globalvars.meteo_data.abs_pressure = None if (self.cfg.use_bmp085): sensor.Sensor.ReadBMP085_temp_in(self) sensor.Sensor.GetData(self) else: log("Meteo : Error in getting data - status = " + str(globalvars.meteo_data.status)) self.error = False except IOError, e: #raise log("ERROR with PCE-FWS20 %s . Will retry ..." % e) # ret,self.model,self.idd,self.bus = self.Detect() # usbdevice = "/dev/bus/usb/%s/%s" % (self.idd , self.bus ) # os.system( "./usbreset %s" % (usbdevice) ) self.__init__(self.cfg) self.error = True
def main(): station = WeatherStation.WeatherStation() phone = PhoneWeatherService.PhoneWeatherService(station) station.Add(phone) station.Run()
#!/usr/bin/env python # checkWeather.py # # Print current weather conditions. import sys sys.path.append('../customLibraries') import WeatherStation # Check arguments. if 1 != len(sys.argv): print "Usage:\n checkWeather.py" exit(1) # Create a WeatherStation object. ws = WeatherStation.WeatherStation("/home/pi/data/weatherData.csv") # Get down to business. ws.fetchData() ws.printData()
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 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 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 sys.version_info < (2, 5) or not self.use_locale: yield fmt % (x) elif sys.version_info < (2, 7) and '%%' in fmt: yield locale.format_string(fmt.replace('%%', '##'), x).replace('##', '%') else: yield locale.format_string(fmt, x) 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 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 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 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]] if command[0] == 'wind_dir' and data['wind_ave'] < 0.3: x = None # 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 sys.version_info < (2, 5): yield fmt % (x) elif sys.version_info < (2, 7) and '%%' in fmt: yield locale.format_string( fmt.replace('%%', '##'), x).replace('##', '%') else: yield locale.format_string(fmt, x) 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
F = 0.2314 * (1030.81 - pressure) LUT = ('A', 'B', 'B', 'B', 'E', 'K', 'N', 'N', 'P', 'P', 'S', 'W', 'W', 'X', 'X', 'X', 'Z') # clip to range of lookup table F = min(max(int(F + 0.5), 0), len(LUT) - 1) # convert to letter code return LUT[F] def ZambrettiText(letter): return forecast_text[letter] if __name__ == "__main__": import WeatherStation wind_dir = WeatherStation.get_wind_dir_text() for pressure in range(1030, 960, -10): for trend_txt in ('S', 'R-S', 'R-W', 'F-W', 'F-S'): trend, month = { 'R-W': (0.2, 1), 'F-W': (-0.2, 1), 'R-S': (0.2, 7), 'F-S': (-0.2, 7), 'S': (0.0, 7), }[trend_txt] for wind in (0, 2, 14, None, 4, 12, 6, 10, 8): if wind == None: wind_txt = 'calm' else: wind_txt = wind_dir[wind] print '%4d %4s %4s %3s' % (pressure, trend_txt, wind_txt,
#!/usr/bin/env python # recordWeather.py # # Record the current weather conditions. import sys from optparse import OptionParser sys.path.append('../customLibraries') import WeatherStation # Use OptionParser to grab command-line options. parser = OptionParser() parser.add_option('-f', '--file', dest='dataFile', help='Write weather data to CSVFILE.', metavar='CSVFILE') (options, args) = parser.parse_args() # Supply a default filename, if necessary. if None == options.dataFile: dataFile = '../data/weatherData.csv' else: dataFile = options.dataFile # Create a WeatherStation object. ws = WeatherStation.WeatherStation(dataFile=dataFile) # Get down to business. ws.fetchData() ws.recordData() ws.printData()
else: # steady F = 0.2314 * (1030.81 - pressure) LUT = ('A', 'B', 'B', 'B', 'E', 'K', 'N', 'N', 'P', 'P', 'S', 'W', 'W', 'X', 'X', 'X', 'Z') # clip to range of lookup table F = min(max(int(F + 0.5), 0), len(LUT) - 1) # convert to letter code return LUT[F] def ZambrettiText(letter): return forecast_text[letter] if __name__ == "__main__": import WeatherStation wind_dir = WeatherStation.get_wind_dir_text() for pressure in range(1030, 960, -10): for trend_txt in ('S', 'R-S', 'R-W', 'F-W', 'F-S'): trend, month = { 'R-W' : ( 0.2, 1), 'F-W' : (-0.2, 1), 'R-S' : ( 0.2, 7), 'F-S' : (-0.2, 7), 'S' : ( 0.0, 7), }[trend_txt] for wind in (0, 2, 14, None, 4, 12, 6, 10, 8): if wind == None: wind_txt = 'calm' else: wind_txt = wind_dir[wind] print '%4d %4s %4s %3s' % (