Sorry I was gone for a little bit. Here is my code that uses Python to interface into the 8 pulse wind sensor. I basically setup an GPIO.add_event_detect to count the pulses from the wind sensor. Then every "second" I sum the count and apply the correct multipliers. I time stamp every "second" as that tends to drift based on the load on the system. I than take the correct time interval (normally 1 second but can be as long as 1.7 seconds) to correct my value. Here is the code. import math
import spidev
import RPi.GPIO as GPIO
import time
from time import strftime, localtime
# Global variables
wind_start_time = time.time()
wind_pulse_cnt = 0
peak_3s_wind = []
wind_dir_adc_min = float(.15) # Zero degree wind dir is around .1 volts
wind_dir_adc_max = float(3.05) # 360 degree wind dir is around 3 volts
# ------------------CONFIGURATION--------------------------
# Wind speed
wind_10m_multiplier = float(4.02336) / float(8) # km/h
wind_10m_GPIO_port = 22
# Wind Direction
wind_dir_channel = 0
wind_dir_offset = 171 # Degrees to rotate CC to equal actual direction.
# ------------------END OF CONFIGURATION --------------------
# Configure the GPIO for the RPi
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# Open spi port to ADC
spi = spidev.SpiDev()
spi.open(0, 0) # 12bit ADC MCP3208
spi.max_speed_hz = (500000)
# Function that counts pulses from 10m wind sensor
def callback_windsp_10m(channel):
global wind_pulse_cnt
wind_pulse_cnt += 1
# monitor GPIO for pulses from wind sensor
GPIO.add_event_detect(wind_10m_GPIO_port,
GPIO.FALLING,
callback=callback_windsp_10m,
bouncetime=1)
# Function to get data from Wind Speed Sensor
# Wind speed sends 8 pulses per revolution. Time is need to complete
# calculations. Normally this is one second but delays in program
# run time can change that. We use wind_end_time and wind_start_time
# to correctly get the time inverval between obs.
def get_10m_wind_speed():
global wind_pulse_cnt
global wind_start_time
global peak_3s_wind
wind_end_time = time.time()
wind_speed = ((wind_pulse_cnt * wind_10m_multiplier) /
(wind_end_time - wind_start_time))
wind_pulse_cnt = 0 # reset counter
wind_start_time = wind_end_time # Reset timer for winds
peak_3s_wind.insert(0, wind_speed)
if len(peak_3s_wind) == 4:
peak_3s_wind.pop()
avg_peak_wind = 0
for peak_wind in peak_3s_wind:
avg_peak_wind = avg_peak_wind + peak_wind
avg_peak_wind = float(avg_peak_wind / len(peak_3s_wind))
return wind_speed, avg_peak_wind
# Function to get data from Wind Vane Sensor
def get_10m_wind_dir():
global wind_dir_adc_min, wind_dir_adc_max
# single-ended measurement see mcp3208_test for differental code
r1 = spi.xfer2([6 + (wind_dir_channel >> 2),
(wind_dir_channel & 3) << 6,
0])
adcout1 = float(((r1[1] & 15) << 8) + r1[2]) / float(4095) * 3.3
# This dynamically changes the range of the sensor since it might change.
f = open('/home/weewx/bin/wind_adjustment.txt', 'a')
datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
if adcout1 < wind_dir_adc_min:
wind_dir_adc_min = adcout1
data = "%s Wind adc min changed to : %.2f\n" % (datetime, adcout1)
f.write(data)
if adcout1 > wind_dir_adc_max:
wind_dir_adc_max = adcout1
data = "%s Wind adc max changed to : %.2f\n" % (datetime, adcout1)
f.write(data)
f.close()
wind_dir = round(float((adcout1 - wind_dir_adc_min) /
float(wind_dir_adc_max - wind_dir_adc_min)) *
float(360), 0)
# Apply offset
wind_dir = wind_dir + wind_dir_offset
if wind_dir > 360:
wind_dir = wind_dir - 360
return wind_dir
# Main Program. Sample all the sensors and created data file.
# This data file can then be picked up by ingester (WEEWX)
while True:
# Get time
start_time = time.time()
datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
# Get Wind Direction
winddir_10m = get_10m_wind_dir()
# Get wind speed and three second peak. (WMO standard)
windspd_10m, windspd_peak_10m = get_10m_wind_speed()
if windspd_10m < 0.01: # Wind speed is zero
winddir_10m = None
# Get End Times and calculate program pause to next collection
end_time = time.time()
proc_time = round(end_time - start_time, 4)
if (proc_time > 1) or (math.ceil(end_time) > math.ceil(start_time)):
sleep_time = 0
else:
sleep_time = math.ceil(end_time) - end_time
time.sleep(sleep_time) # Sleep until beginning of next second
My full code is here for anyone who uses similar sensors.
#!/usr/bin/python
# This datalogger script is responsible for collecting meteorological
# information from the following sensors and creating a named pipe that
# streams that information over to the weewx driver.
# Installed sensors:
# SHT25 (Temperature/Humidity sensor) [i2c]
# BMP180 (Pressure) [i2c]
# Pyronometer (homemade) [ADC]
# AS3935 (Lightning sensor) [i2c]
# wxunderweatherstation Wind direction (inspeed) [ADC]
# wxunderweatherstation Wind sensor (Inspeed) [GPIO, pulse]
# Rainwise RAINEW 111 Tipping Bucket Rain Gauge [pulse]
# Last updated: 2015-04-28
# Created by Nickolas McColl
import math
import spidev
import RPi.GPIO as GPIO
import time
from time import strftime, localtime
from Adafruit_BMP085 import BMP085
import sht21
from RPi_AS3935 import RPi_AS3935 # Lightning Sensor
# Global variables
wind_start_time = time.time()
wind_pulse_cnt = 0
peak_3s_wind = []
precip_pulse_cnt = 0
lightning_cnt = 0
distance_sum = 0
wind_dir_adc_min = float(.15) # Zero degree wind dir is around .1 volts
wind_dir_adc_max = float(3.05) # 360 degree wind dir is around 3 volts
current_time = time.time()
temp = None
rh = None
precip_pulse_start_time = 0
precip_pulse_stop_time = 0
# ------------------CONFIGURATION--------------------------
# pressure
pres_mode = 1 # (0 ultralow power, 1 std, 2 high res, 3 ultrahigh res)
bmp = BMP085(0x77, pres_mode) # BMP085 and BMP180 are identical
# Solar
solar_channel = 4
solar_multi = 5113 # taken from calibration at work
# Wind speed
wind_10m_multiplier = float(4.02336) / float(8) # km/h
wind_10m_GPIO_port = 22
# Wind Direction
wind_dir_channel = 0
wind_dir_offset = 171 # Degrees to rotate CC to equal actual direction.
# Lightning Sensor
GPIO.setmode(GPIO.BCM)
sensor = RPi_AS3935(address=0x03, bus=1)
sensor.calibrate(tun_cap=0x0F)
sensor.set_indoors(False)
sensor.set_noise_floor(0)
lightning_port = 23 #
# Precipitation
precip_port = 27
precip_multi = 0.0254 # Centimeters per tip
# ------------------END OF CONFIGURATION --------------------
# Configure the GPIO for the RPi
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(17, GPIO.OUT) # Rain activity (Blue)
GPIO.setup(18, GPIO.OUT) # Status activity (green)
GPIO.setup(wind_10m_GPIO_port, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(lightning_port, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(precip_port, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Open spi port to ADC
spi = spidev.SpiDev()
spi.open(0, 0) # 12bit ADC MCP3208
spi.max_speed_hz = (500000)
# Function that counts pulses from 10m wind sensor
def callback_windsp_10m(channel):
global wind_pulse_cnt
wind_pulse_cnt += 1
# Function that counts rain
def callback_precip(channel):
global precip_pulse_cnt
#precip_pulse_cnt = precip_pulse_cnt + 1 # each tip 1/100 inch
f = open('/home/weewx/bin/rain.log', 'a')
datetime = strftime("%Y-%m-%d %H:%M:%S ", localtime())
f.write(datetime + ' Precip detected 0.01 \n')
f.close()
# turn off precip until error fixed. Make sure to turn it on below as well
precip_pulse_cnt = 0
# Function that counts lightning strikes
def handle_interrupt(channel):
time.sleep(0.003)
global sensor
reason = sensor.get_interrupt()
f = open('/home/weewx/bin/lightning', 'a')
datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
if reason == 0x01:
f.write(datetime + ': Noise level too high - adjusting \n')
sensor.raise_noise_floor() # Too much noise adjust
elif reason == 0x04:
f.write(datetime + ': Masking disturber\n')
sensor.set_mask_disturber(True) # Masking disturber
elif reason == 0x08:
f.write(
datetime + ': Storm is ' +
sensor.get_distance() + ' miles away!\n')
global lightning_cnt, distance_sum
GPIO.output(17, True)
distance_sum = distance_sum + sensor.get_distance()
lightning_cnt = lightning_cnt + 1
GPIO.output(17, False)
else:
f.write(datetime + 'Called but nothing to do\n')
f.close()
# monitor GPIO for pulses from wind sensor
GPIO.add_event_detect(wind_10m_GPIO_port,
GPIO.FALLING,
callback=callback_windsp_10m,
bouncetime=1)
# Monitor GPIO for lightning
GPIO.add_event_detect(lightning_port,
GPIO.FALLING,
callback=handle_interrupt)
# Monitor GPIO for Rain
GPIO.add_event_detect(precip_port,
GPIO.FALLING,
callback=callback_precip,
bouncetime=300)
# function to get data from SHT25.
def get_sfc_temprh():
# Sample temp/rh ever 2 seconds. Alternate measurements.
global temp, rh
if (math.floor(time.time()) % 2) == 0:
temp = sht21.SHT21(1).read_temperature()
else:
rh = sht21.SHT21(1).read_humidity()
if (rh > 100):
rh = 100
return temp, rh
# Function to get data from Pressure sensor
def get_sfc_pres():
global bmp
if bmp:
pres = bmp.readPressure()
pres = (pres / float(100)) # Converts to hPa
else:
pres = None
return pres
# Function to get data from Solar Sensor
def get_solar():
# Single ended measurement
samples = 100
value_sum = 0
for i in range(0, samples):
r2 = spi.xfer2([6 + (solar_channel >> 2), (solar_channel & 3) << 6, 0])
adcout2 = ((r2[1] & 15) << 8) + r2[2]
value_sum = adcout2 + value_sum
value_avg = float(float(value_sum / samples))
solar = round(float(value_avg) / (4095) * float(3.3) *
float(solar_multi), 1)
if solar < 5:
solar = 0
return solar
# Function to get data from Rain Gauge
def get_precip():
global precip_pulse_cnt
# precip = precip_pulse_cnt * precip_multi
# precip_pulse_cnt = 0
precip = None
return precip
# Function to get data from Wind Speed Sensor
# Wind speed sends 8 pulses per revolution. Time is need to complete
# calculations. Normally this is one second but delays in program
# run time can change that. We use wind_end_time and wind_start_time
# to correctly get the time inverval between obs.
def get_10m_wind_speed():
global wind_pulse_cnt
global wind_start_time
global peak_3s_wind
wind_end_time = time.time()
wind_speed = ((wind_pulse_cnt * wind_10m_multiplier) /
(wind_end_time - wind_start_time))
wind_pulse_cnt = 0 # reset counter
wind_start_time = wind_end_time # Reset timer for winds
peak_3s_wind.insert(0, wind_speed)
if len(peak_3s_wind) == 4:
peak_3s_wind.pop()
avg_peak_wind = 0
for peak_wind in peak_3s_wind:
avg_peak_wind = avg_peak_wind + peak_wind
avg_peak_wind = float(avg_peak_wind / len(peak_3s_wind))
return wind_speed, avg_peak_wind
# Function to get data from Wind Vane Sensor
def get_10m_wind_dir():
global wind_dir_adc_min, wind_dir_adc_max
# single-ended measurement see mcp3208_test for differental code
r1 = spi.xfer2([6 + (wind_dir_channel >> 2),
(wind_dir_channel & 3) << 6,
0])
adcout1 = float(((r1[1] & 15) << 8) + r1[2]) / float(4095) * 3.3
# This dynamically changes the range of the sensor since it might change.
f = open('/home/weewx/bin/wind_adjustment.txt', 'a')
datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
if adcout1 < wind_dir_adc_min:
wind_dir_adc_min = adcout1
data = "%s Wind adc min changed to : %.2f\n" % (datetime, adcout1)
f.write(data)
if adcout1 > wind_dir_adc_max:
wind_dir_adc_max = adcout1
data = "%s Wind adc max changed to : %.2f\n" % (datetime, adcout1)
f.write(data)
f.close()
wind_dir = round(float((adcout1 - wind_dir_adc_min) /
float(wind_dir_adc_max - wind_dir_adc_min)) *
float(360), 0)
# Apply offset
wind_dir = wind_dir + wind_dir_offset
if wind_dir > 360:
wind_dir = wind_dir - 360
return wind_dir
# Function to monitor for lightning
def get_lightning():
global lightning_cnt
count = lightning_cnt
lightning_cnt = 0
global distance_sum
if count > 0:
storm_distance = float(distance_sum / count)
else:
storm_distance = 0
distance_sum = 0
# count = None
# storm_distance = None
return count, storm_distance
# Function to get RPi's temperature
def get_pi_temp():
f = open('/sys/class/thermal/thermal_zone0/temp', 'r')
input = f.readline()
if input:
system_temp = float(input) / 1000
else:
system_temp = None
return system_temp
# Main Program. Sample all the sensors and created data file.
# This data file can then be picked up by ingester (WEEWX)
while True:
GPIO.output(18, True) # turn led status light on.
GPIO.output(17, False) # turn lightning status light off.
# Get time
start_time = time.time()
datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
# Get Temperature and Humidity
temperature_sfc, humidity_sfc = get_sfc_temprh()
# Get Pressure
pressure_sfc = get_sfc_pres()
# Get Wind Direction
winddir_10m = get_10m_wind_dir()
# Get wind speed and three second peak. (WMO standard)
windspd_10m, windspd_peak_10m = get_10m_wind_speed()
if windspd_10m < 0.01: # Wind speed is zero
winddir_10m = None
# Get Solar
solar_sfc = get_solar()
# Get Precip
precip_sfc = get_precip()
# Get Lightning Data
total_lightning, lightning_distance = get_lightning()
# Get System temperature
system_temp = get_pi_temp()
# Get End Times and calculate program pause to next collection
end_time = time.time()
proc_time = round(end_time - start_time, 4)
if (proc_time > 1) or (math.ceil(end_time) > math.ceil(start_time)):
sleep_time = 0
else:
sleep_time = math.ceil(end_time) - end_time
# Build data string
data = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (
datetime, pressure_sfc, windspd_10m,
winddir_10m, temperature_sfc, humidity_sfc,
precip_sfc, total_lightning, lightning_distance,
solar_sfc, proc_time, system_temp, windspd_peak_10m)
filename = time.strftime("%Y-%m-%d")
# Write data to archive
log = open('/home/weewx/data/' + filename + '.csv', 'a')
log.write(data)
log.close()
# Write current data
log2 = open('/home/weewx/bin/wxdata.csv', 'w')
log2.write(data)
log2.close()
GPIO.output(18, False) # turn led status light off
time.sleep(sleep_time) # Sleep until beginning of next second