I have attached the byows_rpi.py file that I am using currently. Some of the values haven't been changed for my equipment just yet. I need to add the ground temp serial number and some additional wind vane values.
Many thanks for your time and energy here! On Sat, Jul 23, 2022 at 3:51 PM Tom Keffer <[email protected]> wrote: > Something is off. Could you send me the copy of byows_rpi.py you are > using? > > > On Sat, Jul 23, 2022 at 2:33 PM Jan Bennett <[email protected]> wrote: > >> Thank you for your time in responding. >> >> It is correct that byows_rpi extension >> <https://github.com/jardiamj/BYOWS_RPi> is mostly just a python file >> (byows_rpi.py) saved to /usr/share/weewx/user/ >> >> I have followed the directions at the git repository and have verified >> with Change Driver <https://github.com/weewx/weewx/wiki/Change-driver> >> that I've done the appropriate things to weewx.conf as well. >> >> When I run either of the commands you listed I receive the same error as >> before: >> >> class ByowsRpi(weewx.drivers.AbstractDevice) >> NameError: name 'weewx' is not defined >> >> >> >> On Saturday, July 23, 2022 at 9:02:42 AM UTC-6 [email protected] wrote: >> >>> 1, It looks like the byows_pi extension does not use the extension >>> installer, so weewx has no way of knowing of its existence. This is why it >>> doesn't show up in the list of available drivers. >>> >>> 2. As for running byows_pi directly, you have a slight problem with your >>> paths. Try either this >>> >>> cd /usr/share/weewx >>> python user/byows_rpi.py >>> >>> >>> or this >>> >>> cd /usr/share/weewx >>> python -m user.byows_rpi >>> >>> >>> -tk >>> >>> On Sat, Jul 23, 2022 at 6:12 AM Jan Bennett <[email protected]> wrote: >>> >>>> I should also note that when I 'sudo wee_config --reconfigure >>>> --driver=user.byows_rpi --no-prompt' I see the following: >>>> >>>> Using configuration file /home/weewx/weewx.conf >>>> Driver user.byows_rpi failed to load: name 'weewx' is not defined >>>> >>>> On Saturday, July 23, 2022 at 7:07:55 AM UTC-6 Jan Bennett wrote: >>>> >>>>> Hey all - >>>>> >>>>> I am trying to install the driver for the Build Your Own Weather >>>>> Station using Raspberry pi (byows_rpi.py) >>>>> >>>>> I have updated weewx-config to include BYOWS. I also have the >>>>> interceptor driver installed. >>>>> >>>>> However, I cannot seem to get the driver to show up under the drivers >>>>> list when I try 'wee_config --list-drivers'. I show byows_rpi.py under >>>>> /usr/share/weewx/user/ >>>>> >>>>> I have tried 'sudo wee_config --reconfigure --driver=user.byows_rpi >>>>> --no-promt' to no avail. >>>>> >>>>> I feel like I've missed a step somewhere about how to actually get the >>>>> system to recognize the driver. >>>>> >>>>> When I try to run the byows_rpi.py via command line from within the >>>>> /usr/share/weewx/user/ folder: 'python3 byows_rpi.py' I see the following >>>>> error: >>>>> >>>>> class ByowsRpi(weewx.drivers.AbstractDevice) >>>>> NameError: name 'weewx' is not defined >>>>> >>>>> Any guidance would be greatly appreciated! >>>>> >>>> -- >>>> 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]. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/weewx-user/074ed02d-872f-4384-82bf-748449e13ef5n%40googlegroups.com >>>> <https://groups.google.com/d/msgid/weewx-user/074ed02d-872f-4384-82bf-748449e13ef5n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >> 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]. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/weewx-user/c207e67c-2fb6-4a4c-812d-867387566476n%40googlegroups.com >> <https://groups.google.com/d/msgid/weewx-user/c207e67c-2fb6-4a4c-812d-867387566476n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- > You received this message because you are subscribed to a topic in the > Google Groups "weewx-user" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/weewx-user/wtQ92_3SGe8/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/weewx-user/CAPq0zED6%3DO2-mjrfCdB9N%3DkwNoHdoh429f9aeDtw_4KFSVSFMw%40mail.gmail.com > <https://groups.google.com/d/msgid/weewx-user/CAPq0zED6%3DO2-mjrfCdB9N%3DkwNoHdoh429f9aeDtw_4KFSVSFMw%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > -- 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]. To view this discussion on the web visit https://groups.google.com/d/msgid/weewx-user/CAJiLD_AJp7f4XJZYGCxrSr9fy8%3DX14sDrQMWTQ_-ACPr8_Jx%2Bw%40mail.gmail.com.
#!/usr/bin/env python3 """ Copyright 2019 Jardi A. Martinez Jordan <[email protected]> This is an weeWX driver implementation of the Build Your OWN Weather Station using the Raspberry Pi: https://projects.raspberrypi.org/en/projects/build-your-own-weather-station/ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. """ import math import syslog import time import datetime # Imports specific for ByowsRpiStation class from gpiozero import Button, MCP3008 import os, glob import bme280 import smbus2 DRIVER_NAME = "BYOWS" DRIVER_VERSION = "0.51" def loader(config_dict, _): return ByowsRpi(**config_dict[DRIVER_NAME]) """ def confeditor_loader(): return ByowsRpiConfEditor() """ def logmsg(level, msg): syslog.syslog(level, "BYOWS RPi: %s" % msg) def logdbg(msg): logmsg(syslog.LOG_DEBUG, msg) def loginf(msg): logmsg(syslog.LOG_INFO, msg) def logerr(msg): logmsg(syslog.LOG_ERR, msg) class ByowsRpi(weewx.drivers.AbstractDevice): """weewx driver for the Build Your Own Weather Station - Raspberry Pi """ def __init__(self, **stn_dict): self.hardware = stn_dict.get("hardware", "BYOWS - Raspberry Pi") self.loop_interval = float(stn_dict.get("loop_interval", 5)) params = dict() params["anem_pin"] = int(stn_dict.get("anemometer_pin", 5)) params["rain_bucket_pin"] = int(stn_dict.get("rain_bucket_pin", 6)) params["bme280_port"] = int(stn_dict.get("bme280_port", 1)) params["bme280_address"] = int(stn_dict.get("bme280_address", "0x77"), 16) params["mcp3008_channel"] = int(stn_dict.get("mcp3008_channel", 0)) params["anem_adjustment"] = float(stn_dict.get("anemometer_adjustment", 1.18)) params["bucket_size"] = float(stn_dict.get("bucket_size", 0.2794)) params["anem_radius_cm"] = float(stn_dict.get("anemometer_radius_cm", 9.0)) loginf("using driver %s" % DRIVER_NAME) loginf("driver version is %s" % DRIVER_VERSION) self.station = ByowsRpiStation(**params) @property def hardware_name(self): return self.hardware def genLoopPackets(self): """ Function that generates packets for weeWX by looping through station data generator function. """ while True: packet = {"dateTime": int(time.time() + 0.5), "usUnits": weewx.METRIC} data = self.station.get_data() packet.update(data) yield packet time.sleep(self.loop_interval) # defaults to 5 seconds class ByowsRpiStation(object): """ Object that represents a BYOWS_Station. """ CM_IN_A_KM = 100000.0 SECS_IN_AN_HOUR = 3600 def __init__(self, **params): """ Initialize Object. """ self.bme280_address = params.get("bme280_address") self.bme280_bus = smbus2.SMBus(params.get("bme280_port")) self.bme280_sensor = bme280 self.bme280_sensor.load_calibration_params(self.bme280_bus, self.bme280_address) self.bucket_size = params.get("bucket_size") # in mm self.rain_count = 0 self.wind_gauge = WindGauge( params.get("mcp3008_channel"), params.get("anem_pin"), params.get("anem_radius_cm"), params.get("anem_adjustment"), ) self.rain_sensor = Button(params.get("rain_bucket_pin")) self.rain_sensor.when_pressed = self.bucket_tipped self.temp_probe = DS18B20() def bucket_tipped(self): self.rain_count = self.rain_count + 1 def get_bme280_data(self): try: data = self.bme280_sensor.sample(self.bme280_bus, self.bme280_address) humidity = data.humidity pressure = data.pressure temperature = data.temperature except: logdbg("Error sampling sensor bme280, passing None as data.") humidity, pressure, temperature = None, None, None pass return humidity, pressure, temperature def get_soil_temp(self): return self.temp_probe.read_temp() def get_rainfall(self): """ Returns rainfall in cm. """ rainfall = (self.rain_count * self.bucket_size) / 10.0 self.reset_rainfall() return rainfall def get_data(self): """ Generates data packets every time interval. """ data = dict() anem_rotations = self.wind_gauge.wind_count / 2.0 time_interval = self.wind_gauge.last_wind_time - time.time() wind_speed, wind_dir = self.wind_gauge.get_wind() humidity, pressure, ambient_temp = self.get_bme280_data() data["outHumidity"] = humidity data["pressure"] = pressure data["outTemp"] = ambient_temp data["soilTemp1"] = self.get_soil_temp() data["windSpeed"] = float(wind_speed) data["windDir"] = wind_dir data["rain"] = float(self.get_rainfall()) data["anemRotations"] = anem_rotations data["timeAnemInterval"] = time_interval return data def reset_rainfall(self): self.rain_count = 0 class DS18B20(object): """ add the lines below to /etc/modules (reboot to take effect) w1-gpio w1-therm """ def __init__(self): w1_devices = glob.glob("/sys/bus/w1/devices/28*") self.device_file = w1_devices[0] + "/w1_slave" if len(w1_devices) > 0 else None def read_temp_raw(self): if self.device_file != None: f = open(self.device_file, "r") lines = f.readlines() f.close() return lines else: return None def crc_check(self, lines): return lines[0].strip()[-3:] == "YES" def read_temp(self): temp_c = -255 attempts = 0 lines = self.read_temp_raw() if lines != None: success = self.crc_check(lines) while not success and attempts < 3: time.sleep(0.2) lines = self.read_temp_raw() success = self.crc_check(lines) attempts += 1 if success: temp_line = lines[1] equal_pos = temp_line.find("t=") if equal_pos != -1: temp_string = temp_line[equal_pos + 2 :] temp_c = float(temp_string) / 1000.0 return ((temp_c * 9) / 5 + 32) else: return None class WindGauge(object): """ Object that represents a Wind Vane sensor. """ WIND_VANE_VOLTS = { 0.4: 0.0, 1.4: 22.5, 1.2: 45.0, 2.8: 67.5, 2.7: 90.0, 2.9: 112.5, 2.2: 135.0, 2.5: 157.5, 1.8: 180.0, 2.0: 202.5, 0.7: 225.0, 0.8: 247.5, 0.1: 270.0, 0.3: 292.5, 0.2: 315.0, 0.6: 337.5, } CM_IN_A_KM = 100000.0 SECS_IN_AN_HOUR = 3600 def __init__(self, channel=0, anem_pin=5, anem_radius=9.0, anem_adjustment=1.18): # pass channel of MCP3008 where wind vane is connected to self.adc = MCP3008(channel) self.wind_count = 0 # Counts how many half-rotations self.last_wind_time = time.time() self.wind_speed_sensor = Button(anem_pin) self.wind_speed_sensor.when_pressed = self.spin self.anemometer_radius_cm = anem_radius # Radius of your anemometer self.anemometer_adjustment = anem_adjustment # Every half-rotations, add 1 to count def spin(self): self.wind_count = self.wind_count + 1 def reset_wind(self): self.wind_count = 0 self.last_wind_time = time.time() def get_wind_speed(self): """ Function that returns wind speed in km/hr. """ wind_speed = self.calculate_speed(time.time() - self.last_wind_time) self.reset_wind() # reset wind_count and last time reading return wind_speed def get_wind(self, length=5): """ Function that returns wind as a vector: speed, direction.""" return self.get_wind_speed(), self.read_direction() def calculate_speed(self, time_sec): circumference_cm = (2 * math.pi) * self.anemometer_radius_cm rotations = self.wind_count / 2.0 # Calculate distance travelled by a cup in km dist_km = (circumference_cm * rotations) / self.CM_IN_A_KM # Speed = distance / time km_per_sec = dist_km / time_sec km_per_hour = km_per_sec * self.SECS_IN_AN_HOUR # Calculate Speed final_speed = km_per_hour * self.anemometer_adjustment return final_speed def read_direction(self): wind = round(self.adc.value * 3.3, 1) if not wind in self.WIND_VANE_VOLTS: # keep only good measurements logdbg("Unknown Wind Vane value: %s" % str(wind)) return None else: return self.WIND_VANE_VOLTS[wind] def get_average_direction(self, length=5): # Get the average wind direction in a length of time in seconds data = [] # print("Measuring wind direction for %d seconds..." % length) start_time = time.time() while time.time() - start_time <= length: direction = self.read_direction() if direction is not None: data.append(direction) return get_average(data) def get_average(angles): # Function that returns the average angle from a list of angles sin_sum = 0.0 cos_sum = 0.0 for angle in angles: r = math.radians(angle) sin_sum += math.sin(r) cos_sum += math.cos(r) flen = float(len(angles)) s = sin_sum / flen c = cos_sum / flen arc = math.degrees(math.atan(s / c)) average = 0.0 if s > 0 and c > 0: average = arc elif c < 0: average = arc + 180 elif s < 0 and c > 0: average = arc + 360 return 0.0 if average == 360 else average """ Section for testing purposes, so file can be run outside of weeWX. invoke this as follows from the weewx root dir: PYTHONPATH=bin python bin/weewx/drivers/byows_rpi.py""" if __name__ == "__main__": station = ByowsRpiStation() packet = {"dateTime": int(time.time() + 0.5), "usUnits": weewx.METRIC} interval = 5 data = station.get_data(interval) # defaults to 5 seconds packet.update(data) print(packet)
