Major Changes

This commit is contained in:
Tiwesdaeg Twohands 2019-10-21 11:45:23 -05:00
parent 3ab15d9afc
commit 5e9e706efe
20 changed files with 439 additions and 19 deletions

View File

@ -5,22 +5,22 @@
This is just a little home project I have that mixes gopher,
python, gnuplot, and shell scripting. The sensor is a BME280 that is
connected to a raspberry pi. The page can be accessed at
gopher://perilo.us
connected to a raspberry pi as well as a simple bucket rain sensor.
The page can be accessed at gopher://perilo.us or https://wx.perilo.us.
## Features
It currently gathers temperature, humidity, and air pressure every
ten minutes and writes to a daily log file. This is done via crontab
where wxlog.py is run every 10 minutes. The script wxlog.py also
generates new year/month folders and a new daily log file if they
don't already exist.
It currently gathers temperature, humidity, air pressure, and rainfall.
Temperature, humidity, and air pressure are captured every ten minutes
and writen to a daily log file. This is done by configuring a crontab to
run scripts/wxlog.py every ten minutes. This script also generates new
year/month folders/files and a new daily log file if they don't already
exist. Rain data is gathered by a background process, scripts/rain.py
that must run as a background process to count the number of bucket tips
in the rain sensor. This data is logged in a separate monthly rain folder.
Upon each new gopher request, it provides current weather data. Gnuplot is used to display data graphs in ascii format.
There is now a rain gauge installed. It calculates daily rainfall.
This is done via txt log generated by crontab running rain.py
every 1 minute.
Upon each new gopher request, it provides current weather data. Gnuplot is
used to display data graphs in ascii format.
## Todo

View File

@ -14,12 +14,12 @@ echo "╚═══════════════════════
echo " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒"
echo ""
echo "╔══════════════╗ ╔══════════════╗ ╔══════════════╗ ╔══════════════╗"
sudo python3 /var/gopher/gw.py
sudo python3 /var/gopher/scripts/current_weather.py
echo "╚══════════════╝▒ ╚══════════════╝▒ ╚══════════════╝▒ ╚══════════════╝▒"
echo " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒"
echo ""
echo "╔════════════════════════════════╗ ╔════════════════════════════════╗"
sudo /var/gopher/hilo.py /var/gopher$today
sudo /var/gopher/scripts/hilow_rain.py /var/gopher$today
echo "╚════════════════════════════════╝▒ ╚════════════════════════════════╝▒"
echo " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒"
echo ""

View File

@ -1,4 +1,8 @@
#!/usr/bin/python3
# Generates a temporary file with only dew point data for gnuplot
# to use to generate a dew point plot.
import os
import sys

View File

@ -1,4 +1,8 @@
#!/usr/bin/python3
# Generates a temporary file with only humidity data for gnuplot
# to use to generate a humidity plot.
import os
import sys
import re

View File

@ -1,4 +1,8 @@
#!/usr/bin/python3
# Generates a temporary file with only temperature data for gnuplot
# to use to generate a temperature plot.
import os
import sys
@ -11,7 +15,6 @@ def time_process(s):
def temp_process(s):
sa = s.split()
st = sa[1]
# stemp = st[:5] + "\n"
stemp = st.replace('°F', '') + "\n"
return stemp

View File

@ -1,4 +1,8 @@
#!/usr/bin/python3
# Generates a temporary file with only barometric pressure data for gnuplot
# to use to generate a barometric pressure plot.
import os
import sys
import re

60
scripts/current_weather.py Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/python3
import bme280
import smbus2
from time import sleep
import math
port = 1
address = 0x76 # Adafruit BME280 address. Other BME280s may be different
bus = smbus2.SMBus(port)
def truncate(n, decimals=0):
multiplier = 10 ** decimals
return int(n * multiplier) / multiplier
def get_frost_point_c(t_air_c, dew_point_c):
dew_point_k = 273.15 + dew_point_c
t_air_k = 273.15 + t_air_c
frost_point_k = dew_point_k - t_air_k + 2671.02 / ((2954.61 / t_air_k) + 2.193665 * math.log(t_air_k) - 13.3448)
return frost_point_k - 273.15
def get_dew_point_c(t_air_c, rel_humidity):
A = 17.27
B = 237.7
alpha = ((A * t_air_c) / (B + t_air_c)) + math.log(rel_humidity/100.0)
return (B * alpha) / (A - alpha)
bme280.load_calibration_params(bus,address)
wxdata = bme280.sample(bus,address)
humidity = wxdata.humidity
pressure = wxdata.pressure
pressure_i = wxdata.pressure / 33.863886666667
temperature = wxdata.temperature
temperature_f = (wxdata.temperature * 1.8) + 32
dew_point = get_dew_point_c(wxdata.temperature, wxdata.humidity)
dew_point_f = (dew_point *1.8) + 32
h = round(humidity)
pm = truncate(pressure, 2)
pi = truncate(pressure_i, 2)
tc = truncate(temperature, 2)
tf = truncate(temperature_f, 2)
dp = truncate(dew_point, 2)
df = truncate(dew_point_f, 2)
pm = '%.2f' % pm
if len(pm) == 6:
pm = ' ' + pm
print('║ Temperature ║▒ ║ Humidity ║▒ ║ Pressure ║▒ ║ Dew Point ║▒')
print('║ ║▒ ║ ║▒ ║ ║▒ ║ ║▒')
if h == 100:
print('{0:.2f}°F ║▒ ║ {1}% ║▒ ║ {2} mbar ║▒ ║ {3:.2f}°F ║▒'.format(tf, h, pm, df))
else:
print('{0:.2f}°F ║▒ ║ {1}% ║▒ ║ {2} mbar ║▒ ║ {3:.2f}°F ║▒'.format(tf, h, pm, df))
if int(tc) < 10 and int(dp) < 10:
print('{0:.2f}°C ║▒ ║ ║▒ ║ {1:.2f} inHg ║▒ ║ {2:.2f}°C ║▒'.format(tc, pi, dp))
elif int(tc) > 10 and int(dp) < 10:
print('{0:.2f}°C ║▒ ║ ║▒ ║ {1:.2f} inHg ║▒ ║ {2:.2f}°C ║▒'.format(tc, pi, dp))
else:
print('{0:.2f}°C ║▒ ║ ║▒ ║ {1:.2f} inHg ║▒ ║ {2:.2f}°C ║▒'.format(tc, pi, dp))

138
scripts/hilow_rain.py Executable file
View File

@ -0,0 +1,138 @@
#!/usr/bin/python3
import os
import sys
import bme280
import smbus2
port = 1
address = 0x76 # Adafruit BME280 address. Other BME280s may be different
bus = smbus2.SMBus(port)
bme280.load_calibration_params(bus,address)
wxdata = bme280.sample(bus,address)
temperature = wxdata.temperature
temperature_f = (wxdata.temperature * 1.8) + 32
# Initial variables set at impossible high or low temperatures
high_temp = -100
low_temp = 200
high_cel = -100
low_cel = 200
#
def temp_process(s):
sa = s.split()
st = sa[1]
stemp = st.replace('°F', '')
return stemp
def cel_process(s):
sa = s.split()
st = sa[2]
stemp = st.replace('°C', '')
return stemp
def high(t, h):
global high_temp
if float(t) > high_temp:
high_temp = float(t)
else:
pass
def low(t, l):
global low_temp
if float(t) < low_temp:
low_temp = float(t)
else:
pass
def c_high(t, h):
global high_cel
if float(t) > high_cel:
high_cel = float(t)
else:
pass
def c_low(t, l):
global low_cel
if float(t) < low_cel:
low_cel = float(t)
else:
pass
def rain_file(file):
first = 26
second = 10
f1, f2 = file[:first], file[first:]
s1, s2 = f2[:second], f2[second:]
convert = f1 + "rain/" + s1 + "-rain" + s2
return convert
def rain_calc(file):
f = open(file, 'r')
total = 0
for i in f:
sf = i.split()
rf = sf[1]
total = total + float(rf)
return total
def rain_inch(m):
inch = m * .0393701
return inch
def spacer(s):
length = len(s)
space = 16 - length
if space == 1:
s = s + " "
else:
pass
return s
def spacer_rain(s):
length = len(s)
space = 8 - length
if space == 2:
s = s + " "
elif space == 1:
s = s + " "
else:
pass
return s
def fixer(number):
nt = str(number).split(".")
if len(nt[1]) == 1:
ns = str(number) + "0"
return ns
else:
ns = str(number)
return ns
log_file = sys.argv[-1]
rain = rain_file(log_file)
f = open(log_file, 'r')
for i in f:
if i[0].isdigit():
current = temp_process(i)
cel = cel_process(i)
high(current, high_temp)
low(current, low_temp)
c_high(cel, high_cel)
c_low(cel, low_cel)
else:
pass
#tempf = fixer(round(high_temp, 2)) + "°F/" + str(low_temp) + "°F"
#tempc = fixer(round(high_cel, 2)) + "°C/" + str(low_cel) + "°C"
tempf = fixer(round(high_temp, 2)) + "°F/" + fixer(round(low_temp, 2)) + "°F"
tempc = fixer(round(high_cel, 2)) + "°C/" + fixer(round(low_cel, 2)) + "°C"
rainm = fixer(round(rain_calc(rain), 2)) + "mm"
raini = fixer(round(rain_inch(rain_calc(rain)), 2)) + "in"
print('║ Daily High/Low ║▒ ║ Rainfall ║▒')
print('║ ║▒ ║ ║▒')
print('{0} ║▒ ║ {1} ║▒'.format(spacer(tempf), spacer_rain(raini)))
print('{0} ║▒ ║ {1} ║▒'.format(tempc, spacer_rain(rainm)))

60
scripts/rain.py Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/python3
import RPi.GPIO as GPIO
import time as t
import datetime
# this many mm per bucket tip
CALIBRATION = 0.2794
# which GPIO pin the gauge is connected to
PIN = 25
# file to log rainfall data in
#LOGFILE = "log.csv"
year = datetime.datetime.now().year
m = datetime.datetime.now().month
if 1 <= m <=9:
month = "0" + str(m)
else:
month = str(m)
day = datetime.datetime.now().day
time = datetime.datetime.now().time()
#file_name = str(datetime.datetime.now().date()) + "-rain.txt"
#LOGFILE = "/var/gopher/wxlog/" + str(year) + "/" + month + "/" + file_name
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# variable to keep track of how much rain
rain = 0
# the call back function for each bucket tip
def cb(channel):
global rain
rain = rain + CALIBRATION
# register the call back for pin interrupts
GPIO.add_event_detect(PIN, GPIO.FALLING, callback=cb, bouncetime=300)
# open the log file
#file = open(LOGFILE, "a")
def full_path():
full = "/var/gopher/wxlog/" + str(year) + "/" + month + "/rain/" + str(datetime.datetime.now().date()) + "-rain.txt"
return full
# display and log results
while True:
line = str(datetime.datetime.now().time()) + " " + str(rain)
file = open(full_path(), "a")
file.write(line + "\n")
file.flush()
rain = 0
t.sleep(60)
# close the log file and exit nicely
file.close()
GPIO.cleanup()

34
scripts/rain_totals.py Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/python3
import os
import sys
rtotal = 0
def rain_calc(file):
f = open(file, 'r')
total = 0
for i in f:
sf = i.split()
rf = sf[1]
total = total + float(rf)
return total
def rain_inch(m):
inch = m * .0393701
return inch
directory = sys.argv[-1]
for filename in sorted(os.listdir(directory)):
if filename.endswith(".txt"):
path = os.path.join(directory, filename)
sf = filename.split('-')
date = sf[0] + "/" + sf[1] + "/" + sf[2]
rainm = rain_calc(path)
raini = rain_inch(rainm)
rtotal = rainm + rtotal
print(date , str(round(rainm,2)) + "mm " + str(round(raini,2)) + "in")
else:
continue
print(" ")
print("Monthly Total: " + str(round(rtotal, 2)) + "mm " + str(round(rain_inch(rtotal), 2)) + "in")

97
scripts/wxlog.py Executable file
View File

@ -0,0 +1,97 @@
#!/usr/bin/python3
import bme280
import smbus2
import datetime
import os.path
from pathlib import Path
import math
import shutil
port = 1
address = 0x76 # Adafruit BME280 address. Other BME280s may be different
bus = smbus2.SMBus(port)
year = datetime.datetime.now().year
month = datetime.datetime.now().month
time = datetime.datetime.now().time()
def truncate(n, decimals=0):
multiplier = 10 ** decimals
return int(n * multiplier) / multiplier
def get_dew_point_c(t_air_c, rel_humidity):
"""Compute the dew point in degrees Celsius
:param t_air_c: current ambient temperature in degrees Celsius
:type t_air_c: float
:param rel_humidity: relative humidity in %
:type rel_humidity: float
:return: the dew point in degrees Celsius
:rtype: float
"""
A = 17.27
B = 237.7
alpha = ((A * t_air_c) / (B + t_air_c)) + math.log(rel_humidity/100.0)
return (B * alpha) / (A - alpha)
def entry():
port = 1
address = 0x76 # Adafruit BME280 address. Other BME280s may be different
bus = smbus2.SMBus(port)
bme280.load_calibration_params(bus,address)
wxdata = bme280.sample(bus,address)
humidity = wxdata.humidity
pressure = wxdata.pressure
pressure_i = wxdata.pressure / 33.863886666667
temperature = wxdata.temperature
temperature_f = (wxdata.temperature * 1.8) + 32
dew_point = get_dew_point_c(wxdata.temperature, wxdata.humidity)
dew_point_f = (dew_point * 1.8) +32
h = round(humidity)
pm = truncate(pressure, 2)
pi = truncate(pressure_i, 2)
tc = truncate(temperature, 2)
tf = truncate(temperature_f, 2)
dt_now = datetime.datetime.now()
dt = dt_now.strftime("%H:%M:%S")
dp = truncate(dew_point, 2)
df = truncate(dew_point_f, 2)
entry = '{0} {1:.2f}°F {2:.2f}°C {3}% {4:.2f}mbar {5:.2f}inHg {6:.2f}°F {7:.2f}°C\n'.format(dt, tf, tc, h, pm, pi, df, dp)
return entry
def wx_log(y, m):
if 1 <= m < 10:
month = "0" + str(m)
else:
month = str(m)
dir_path = "/var/gopher/wxlog/" + str(y) + "/" + month
dir_path_rain = "/var/gopher/wxlog/" + str(y) + "/" + month + "/rain"
if not os.path.exists(dir_path):
os.makedirs(dir_path)
os.makedirs(dir_path_rain)
shutil.copy2('/var/gopher/skel/index.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/dp.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/hum.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/plot-d.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/plot-h.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/plot-p.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/plot-t.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/pres.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/temp.dcgi', dir_path)
shutil.copy2('/var/gopher/skel/rtotals.dcgi', dir_path)
file_name = str(datetime.datetime.now().date()) + ".txt"
check_file = Path(dir_path + "/" + file_name)
whole_path = dir_path + "/" + file_name
if check_file.is_file():
f = open(whole_path, 'a')
f.write(entry())
else:
f = open(whole_path, 'a')
f.write("WX Station perilo.us # Hernando, MS # " + str(datetime.datetime.now().date()) + "\n")
f.write("------------------------------------------------------------------\n")
f.write(" Time | Temperature | Humidity | Air Pressure | Dew Point\n")
f.write("------------------------------------------------------------------\n")
f.write(entry())
wx_log(year, month)

View File

@ -1,5 +1,7 @@
#!/bin/sh
# Generates a gophermap with gopher links to plot dew point for each day of the given month.
local_dir=$(pwd)
gopher_dir=$(pwd | cut -c 12-)

View File

@ -1,5 +1,7 @@
#!/bin/sh
# Generates a gophermap with gopher links to plot humidity for each day of the given month.
local_dir=$(pwd)
gopher_dir=$(pwd | cut -c 12-)

View File

@ -1,6 +1,8 @@
#!/bin/sh
filename=$2
# Takes a daily log file and generates a plot for dew point.
/var/gopher/plot/dplot.py $filename
gnuplot -e "set terminal dumb; set xdata time; set timefmt '"%H:%M"'; plot '/tmp/temp.tsv' using 1:2 w l title ''" >> /tmp/plot.txt
sed -i '1d' /tmp/plot.txt

View File

@ -1,6 +1,8 @@
#!/bin/sh
filename=$2
# Takes a daily log file and generates a plot for humidity.
/var/gopher/plot/hplot.py $filename
gnuplot -e "set terminal dumb; set xdata time; set timefmt '"%H"'; plot '/tmp/temp.tsv' using 1:2 w l title ''" >> /tmp/plot.txt
sed -i '1d' /tmp/plot.txt

View File

@ -1,6 +1,8 @@
#!/bin/sh
filename=$2
# Takes a daily log file and generates a plot for barometric pressure.
/var/gopher/plot/pplot.py $filename
gnuplot -e "set terminal dumb; set xdata time; set timefmt '"%H:%M"'; plot '/tmp/temp.tsv' using 1:2 w l title ''" >> /tmp/plot.txt
sed -i '1d' /tmp/plot.txt

View File

@ -1,6 +1,8 @@
#!/bin/sh
filename=$2
# Takes a daily log file and generates a plot for temperature.
/var/gopher/plot/plot.py $filename
gnuplot -e "set terminal dumb; set xdata time; set timefmt '"%H:%M"'; plot '/tmp/temp.tsv' using 1:2 w l title ''" >> /tmp/plot.txt
sed -i '1d' /tmp/plot.txt

View File

@ -1,5 +1,7 @@
#!/bin/sh
# Generates a gophermap with gopher links to plot barometric pressure for each day of the given month.
local_dir=$(pwd)
gopher_dir=$(pwd | cut -c 12-)

View File

@ -1,6 +1,6 @@
#!/bin/bash
dir=$(pwd)
for filename in $dir/rain/*; do
/var/gopher/rain_totals.py $filename
done
# Generates a gophermap that lists the daily and monthly totals for the given month.
dir=$(pwd)
/var/gopher/scripts/rain_totals.py $dir/rain

View File

@ -1,5 +1,7 @@
#!/bin/sh
# Generates a gophermap with gopher links to plot temperature for each day of the given month.
local_dir=$(pwd)
gopher_dir=$(pwd | cut -c 12-)