I recently came across a really excellent solution for putting together your own weather station on the cheap with high quality sensors - and most importantly a very useful weather HAT to use with a Raspberry PI to connect all the sensors.
It comes complete with a 4 part step by step tutorial to assemble the whole station, and basic code to upload the data to and online service - see link below: https://www.bc-robotics.com/tutorials/raspberry-pi-weather-station-part-1/ I completed my own installation based on the instructions in the tutorial and my station running on weewx is active at the link below http://peachlandweather.ca/mystation/ For the outdoor portion I used a Raspberry Pi Zero W, with the weather HAT. Weewx is running indoors in a FreeBSD jail, using a stock Interceptor driver. I modified the basic upload code provided in the tutorial quite extensively to generate upload loops that matched the Observer URLs supported by the Interceptor driver, and also to produce derived observations not included in the original code. The upload code is attached for anyone who might be interested in trying to assemble their own. I tested the results from using the station against my Vantage Pro 2 and so far it seems to be pretty close - for less than 20% of the cost of a Vantage Pro. -- You received this message because you are subscribed to the Google Groups "weewx-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
#!/usr/bin/python import time import datetime from w1thermsensor import W1ThermSensor from Adafruit_BME280 import * import Adafruit_ADS1x15 import RPi.GPIO as GPIO import requests import syslog import pickle ds18b20 = W1ThermSensor() bme = BME280(t_mode=BME280_OSAMPLE_8, p_mode=BME280_OSAMPLE_8, h_mode=BME280_OSAMPLE_8) adc = Adafruit_ADS1x15.ADS1115() ## Settings to control operation of weather station interval = 15 #How long we want to wait between loops (seconds) loglevel = 0 #Set to 0 for no log entries, set to 1 for basic log info and 2 for all log info upload_url = "http://192.168.0.29" #IP address or URL to upload data, inlcude port number if not standard filename = "/home/pi/dailyrainfile" ## Init settings for variable - do not adjust windTick = 0 #Used to count the number of times the wind speed input is triggered rainTick = 0 #Used to count the number of times the rain input is triggered ticktimenow = None # Used to calculate the wind gust be determining the shortest time between windTicks mindeltatime = None # Used to calculate the wind gust be determining the shortest time between windTicks looptimenow = time.time() #Used to calculate the wind gust be determining the shortest time between windTicks #load previous saved dailyrain value try: infile = open(filename,'rb') saved_dailyrain = pickle.load(infile) infile.close() dailyrain = saved_dailyrain syslog.syslog("Loading of saved dailyrain state success. Initialise dailyrain to %s" % dailyrain) except: syslog.syslog("Loading of saved dailyrain state failed. Initialise dailyrain to zero") dailyrain = 0 #Set GPIO pins to use BCM pin numbers GPIO.setmode(GPIO.BCM) #Set digital pin 17 to an input and enable the pullup GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Set digital pin 23 to an input and enable the pullup GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Event to detect wind (4 ticks per revolution) GPIO.add_event_detect(17, GPIO.BOTH) def windtrig(self): global windTick windTick += 1 global ticktimenow if ticktimenow is None: ticktimenow = time.time() else: ticktimelast = ticktimenow ticktimenow = time.time() tickdelta = ticktimenow - ticktimelast # print 'Delta time: ' , tickdelta, 'Seconds' global mindeltatime if mindeltatime is None: mindeltatime = tickdelta else: if tickdelta < mindeltatime: mindeltatime = tickdelta # print 'Min Delta Time: ' , mindeltatime, 'Seconds' GPIO.add_event_callback(17, windtrig) #Event to detect rainfall tick GPIO.add_event_detect(23, GPIO.FALLING) def raintrig(self): global rainTick rainTick += 1 GPIO.add_event_callback(23, raintrig) #Function to determine the start of day timestamp def startOfDay(time_ts): """Calculate the unix epoch time for the start of a (local time) day. time_ts: A timestamp somewhere in the day for which the start-of-day is desired. returns: The timestamp for the start-of-day (00:00) in unix epoch time. """ _time_tt = time.localtime(time_ts) _bod_ts = time.mktime((_time_tt.tm_year, _time_tt.tm_mon, _time_tt.tm_mday, 0, 0, 0, 0, 0, -1)) return int(_bod_ts) while True: time.sleep(interval) #Pull Temperature from DS18B20 outtemp = ds18b20.get_temperature() #tempf = (tempc * 9 / 5) + 32 #Pull temperature from BME280 case_temp = bme.read_temperature() #Pull pressure from BME280 Sensor & convert to kPa pressure_pa = bme.read_pressure() absbaro = pressure_pa / 100 #Pull humidity from BME280 outhumi = bme.read_humidity() #Calculate wind direction based on ADC reading try: val = adc.read_adc(0, gain=1) #Read ADC channel 0 with a gain setting of 1 if 20000 <= val <= 20500: winddir = 0 if 10000 <= val <= 10500: winddir = 22.5 if 11500 <= val <= 12000: winddir = 45 if 2000 <= val <= 2250: winddir = 67.5 if 2300 <= val <= 2500: winddir = 90 if 1500 <= val <= 1950: winddir = 112.5 if 4500 <= val <= 4900: winddir = 135 if 3000 <= val <= 3500: winddir = 157.5 if 7000 <= val <= 7500: winddir = 180 if 6000 <= val <= 6500: winddir = 202.5 if 16000 <= val <= 16500: winddir = 225 if 15000 <= val <= 15500: winddir = 247.5 if 24000 <= val <= 24500: winddir = 270 if 21000 <= val <= 21500: winddir = 292.5 if 22500 <= val <= 23000: winddir = 315 if 17500 <= val <= 18500: winddir = 337.5 except: winddir = None syslog.syslog('Wind Direction Input not valid') #Calculate average windspeed over the last 15 seconds windspeed = (windTick * 1.2) / interval # print 'Wind Ticks: ' , windTick windTick = 0 if mindeltatime is not None: maxticks = 1 / mindeltatime windgust = maxticks * 1.2 mindeltatime = None else: windgust = 0 maxticks = 0 #Calculate accumulated rainfall over the last 15 seconds rain = rainTick * 0.2794 #Calculate accumulated rainfull over the last calendar day looptimelast = looptimenow looptimenow = time.time() if startOfDay(looptimelast) == startOfDay(looptimenow): dailyrain = dailyrain + rain else: dailyrain = rain if 'saved_dailyrain' in globals(): if dailyrain <> saved_dailyrain: saved_dailyrain = dailyrain outfile = open(filename,'wb') pickle.dump(saved_dailyrain,outfile) outfile.close() if loglevel == 2: syslog.syslog('Saved updated dailyrain %s' % dailyrain) else: saved_dailyrain = dailyrain outfile = open(filename,'wb') pickle.dump(saved_dailyrain,outfile) outfile.close() if loglevel == 2: syslog.syslog('Daily rain was not previously saved. Saved updated dailyrain %s' % dailyrain) rainTick = 0 if loglevel == 2: #Print the results syslog.syslog('Timestamp: %s' % datetime.datetime.now().strftime("%y-%m-%d %H:%M:%S")) syslog.syslog('Temperature: %s Celsius' % outtemp) syslog.syslog('Board Temp: %s Celsius' % case_temp) syslog.syslog('Humidity: %s percent' % outhumi) syslog.syslog('Pressure: %s hpa' % absbaro) syslog.syslog('Wind Dir: %s degrees' % winddir) syslog.syslog('Wind Speed: %s km/h' % windspeed) syslog.syslog('Wind Gust: %s km/h' % windgust) syslog.syslog('Rainfall: %s mm' % rain) syslog.syslog('Daily Rain: %s mm' % dailyrain) payload = {'outtemp' : outtemp, 'outhumi' : outhumi, 'absbaro' : absbaro, 'windspeed' : windspeed, 'winddir' : winddir, 'windgust' : windgust, 'dailyrain' : dailyrain, 'intemp' : case_temp} try: r = requests.get(upload_url, params=payload) if loglevel >= 1: syslog.syslog(r.url) syslog.syslog(r.text) #Catch the exception if the connection fails except: syslog.syslog(r.url) syslog.syslog("connection failed")
