Here are some notes about the little weather station that is running on my Gemini capsule.
Hardware:
The Pi is within an enclosure with the BME680 hanging off it via a ribbon cable. The assembly is mounted outside but in a relatively sheltered position on a covered balcony. From there it is relatively well protected from the elements whilst still being able to sip from the delightfully tepid and chunky London city air.
To do this, a cron job (take_measurements.py) runs every ten minutes to capture the current temperature, pressure, and humidity. The breakout can also measure "air quality" but it takes some time (about 20 minutes) for the sensor to stablise so I do not use it. The cron job involves running a simple Python script using the bme680 module to take the readings and then write them to a text file. The script appends new readings into a single text file which gradually accumulates data, one timepoint per line and up to 150 readings, i.e. readings from the previous 25 hours. I decided to keep 25 hours as it made thhe subsequent charts showing the 'previous day' easier to read.
A second cron job, offset from the measurement-taking job by two minutes, runs plot_measurements.py to load data from the file, calculate some basic stats, and create the plots. The text-based plots are handled by the termplotlib module and everything is written to a .gmi text file, with the appropriate Gemini formatting. The output file is then rsync'd to the appropriate location on the Gemini server so that you can see it.
The two Python scripts are below:
#!/usr/bin/env python3 #-*- coding: utf-8 -*- import bme680 from datetime import datetime do_gas = False outfile = '/home/pi/weather_log.txt' try: sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY) except (RuntimeError, IOError): sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY) # set a balance between accuracy of reading and # amount of noise. The higher the oversampling, # the greater the reduction in noise, albeit with # a loss of accuracy. sensor.set_humidity_oversample(bme680.OS_2X) sensor.set_pressure_oversample(bme680.OS_4X) sensor.set_temperature_oversample(bme680.OS_8X) sensor.set_filter(bme680.FILTER_SIZE_3) # gas sensor settings if do_gas: sensor.set_gas_status(bme680.ENABLE_GAS_MEAS) sensor.set_gas_heater_temperature(320) sensor.set_gas_heater_duration(150) sensor.select_gas_heater_profile(0) timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # temp, pressure, humidity output = "{0:.2f},{1:.2f},{2:.2f}".format(sensor.data.temperature, sensor.data.pressure, sensor.data.humidity) #if do_gas and sensor.data.heat_stable: # print("{0},{1} Ohms".format(output, sensor.data.gas_resistance)) with open(outfile, 'r') as file_in: data = file_in.read().splitlines(True) data.append(timestamp + ',' + output + '\n') with open(outfile, 'w') as file_out: file_out.writelines(data[-150:])
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import numpy as np from csv import reader import termplotlib as tpl from datetime import datetime input_file = '/home/dave/weather_log.txt' def get_trend(curr_num, avrg_num, norm_range, sensitivity): curr_normd = (curr_num - norm_range[0]) / (norm_range[1] - norm_range[0]) avrg_normd = (avrg_num - norm_range[0]) / (norm_range[1] - norm_range[0]) ratio = curr_normd / avrg_normd thr_upper = (100 + sensitivity) / 100 thr_lower = (100 - sensitivity) / 100 if ratio > thr_upper: ret_trend = 'increasing' elif ratio < thr_lower: ret_trend = 'decreasing' else: ret_trend = 'unchanged' return ret_trend data_times = [] data_temp = [] data_press = [] data_relhum = [] # load the data with open(input_file, "r") as my_file: file_reader = reader(my_file) for i in file_reader: data_times.append(datetime.strptime(i[0], '%Y-%m-%d %H:%M:%S')) data_temp.append(float(i[1])) data_press.append(float(i[2])) data_relhum.append(float(i[3])) # calculate the past 60 minutes average for each measurement avg_temp = sum(data_temp[-7:-1]) / 6 avg_pres = sum(data_press[-7:-1]) / 6 avg_rhum = sum(data_relhum[-7:-1]) / 6 cur_temp = data_temp[-1] cur_pres = data_press[-1] cur_rhum = data_relhum[-1] dir_temp = get_trend(cur_temp, avg_temp, [min(data_temp), max(data_temp)], 5) dir_pres = get_trend(cur_pres, avg_pres, [min(data_press), max(data_press)], 10) dir_rhum = get_trend(cur_rhum, avg_rhum, [min(data_relhum), max(data_relhum)], 15) # write GemText output ... print('# Local Weather Report') print('## London, UK') print('') print('=> gemini://bleyble.com/users/quokka/textcam/index.gmi 📷 Measurements are taken from the same location at the TextCam.') print('=> gemini://bleyble.com/users/quokka/index.gmi ⬑ Go back...') print('') print('### Most Recent Measurements, taken ' + str(data_times[-1]) + ' (UTC)') print('') print('```') print('Measurement \tValue \tUnits \tTrend \t\tMin. \tMax.') print('------------\t------\t------\t------\t\t----\t----') print('Temperature \t' + str(cur_temp) + '\t°C \t' + dir_temp + ' \t' + str(min(data_temp)) + ' \t' + str(max(data_temp))) print('Air Pressure \t' + str(cur_pres) + '\tmbar \t' + dir_pres + ' \t' + str(min(data_press)) + '\t' + str(max(data_press))) print('Rel.Humidity \t' + str(cur_rhum) + '\t% \t' + dir_rhum + ' \t' + str(min(data_relhum)) + ' \t' + str(max(data_relhum))) print('------------\t-----\t-----\t------\t\t----\t----') print('```') print('') print('### Charts - Past Day') x = np.linspace(-25,0,150) ymin = int(np.floor(min(data_temp)/5)*5) ymax = int(np.ceil(max(data_temp)/5)*5) print('```') fig = tpl.figure() fig.plot(x, data_temp, width=75, height=30, xlim=[-26,1], ylim=[ymin,ymax], title='Temperature, last 25 hours') fig.show() print('\t\tHours') print('```') print('') print('') ymin = int(np.floor(min(data_press)/2)*2) ymax = int(np.ceil(max(data_press)/2)*2) print('```') fig = tpl.figure() fig.plot(x, data_press, width=80, height=30, xlim=[-25,1], ylim=[ymin,ymax], title='Pressure, last 25 hours') fig.show() print('\t\tHours') print('```') print('') print('') ymin = int(np.floor(min(data_relhum)/10)*10) ymax = int(np.ceil(max(data_relhum)/10)*10) print('```') fig = tpl.figure() fig.plot(x, data_relhum, width=80, height=30, xlim=[-25,1], ylim=[ymin,ymax], title='Relative Humidity, last 25 hours', extra_gnuplot_arguments='set xlabel') fig.show() print('\t\tHours') print('```') print('') print('=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-') print('') print('=> gemini://bleyble.com/users/quokka/index.gmi ⬑ Go back up a level') print('=> gemini://bleyble.com/users/quokka/index.gmi ↂ Quokka\'s Capsule') print('=> gemini://bleyble.com/index.gmi ↯ bleyble.com')
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
~EOF~