Hello all! So, I've beed doing some searching & reading about how WeeWX handles rain data from various weather station devices. However, it's not clear to me what would the right strategy be in my case.
I'm using a Microbit climate kit <https://www.sparkfun.com/products/16274> and wrote a custom microbit program to serialise and send weather data through USB to a Raspberry pi which feeds it to WeeWX. Similarly, I used weesx-arduino-weather-station <https://github.com/wrybread/weewx-ArduinoWeatherStation> driver as a base driver and modified it for my case. I also read how HP1000 driver handles rain (I read it in a previous post in this forum if I remember correctly) but I can't say I found it enlightening (it probably has to with my level of comprehension for WeeWX code). I attach my version of the driver. It's as simple as I my mind could program it. Please do not pay attention to my current way of reading rain data. I know it doesn't work. If I only correct the data binding, WeeWX stores rain data incrementally for every LOOP packet, as expected. Subsequently, my question is *not* how to retrieve rain data from the weather station, rather than how to feed it to WeeWX in order to get meaningful observations. The limitations on my microbit weather station are these: * No real time clock available on Microbit. I could use uptime, but it's not so useful as the microbit refuses to work properly every few days, so it needs to be reset. I could reset it manually with a cronjob if needed. * Rain data from the weather station only includes one number = bucket tips (which I convert to mm on microbit) which can only go up until microbit is reset - and it *needs* not be reset once in a while. How does one handle the last_rain, total_rain and rain data in WeeWX? The official documentation did not answer my question so if you could point me on the right direction or ideally describe the strategy I should follow, it would be great! Thank you all for your time! Cheers! -- 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/00e5c25d-87c8-4f1d-91ce-2effcb98761an%40googlegroups.com.
#!/usr/bin/env python # # This is a weeWX driver to enable weeWX to read data from a Microbit Climate. # # See here for more details: # # https://github.com/wrybread/ArduinoWeatherStation # # by [email protected] # # # """Driver for Micro:bit Climate weather station. See here for more info: https://google.gr """ from __future__ import with_statement import serial import syslog import time import io from pprint import pprint import weewx.drivers DRIVER_NAME = 'microbit' DRIVER_VERSION = '0.1' def loader(config_dict, _): return MicrobitDriver(**config_dict[DRIVER_NAME]) def confeditor_loader(): return MicrobitConfEditor() INHG_PER_MBAR = 0.0295333727 METER_PER_FOOT = 0.3048 MILE_PER_KM = 0.621371 DEFAULT_PORT = '/dev/ttyACM0' DEBUG_READ = 1 def logmsg(level, msg): syslog.syslog(level, 'Microbit: %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 MicrobitDriver(weewx.drivers.AbstractDevice): """weewx driver that communicates with an Arduino weather station port - serial port [Required. Default is /dev/ttyACM0] polling_interval - how often to query the serial interface, seconds [Optional. Default is 1] max_tries - how often to retry serial communication before giving up [Optional. Default is 5] retry_wait - how long to wait, in seconds, before retrying after a failure [Optional. Default is 10] """ def __init__(self, **stn_dict): self.port = stn_dict.get('port', DEFAULT_PORT) self.polling_interval = float(stn_dict.get('polling_interval', 2)) self.max_tries = int(stn_dict.get('max_tries', 10)) self.retry_wait = int(stn_dict.get('retry_wait', 10)) self.last_rain = None loginf('driver version is %s' % DRIVER_VERSION) loginf('using serial port %s' % self.port) loginf('polling interval is %s' % self.polling_interval) global DEBUG_READ DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) self.last_read_time = time.time() self.read_counter = 0 logdbg("Opening the Arduino on port %s" % self.port) self.baudrate = 115200 self.timeout = 10 # changed from 60 self.serial_port = None try: self.serial_port = serial.Serial(self.port, self.baudrate, timeout=self.timeout) self.serial_port.flush() logdbg("Successfully opened the Arduino.") except Exception as e: logerr("Error opening the Arduino! %s" % e) def read_buffer(self): # read the buffer new_data = "" try: while True: # sio = io.TextIOWrapper(io.BufferedReader(self.serial_port)) # , newline="\r\n") # new_data = sio.readline() # new_data = new_data.replace("\r\n", "") new_data = self.serial_port.read(self.serial_port.inWaiting()).decode('ascii') self.serial_port.flush() return new_data except Exception: print("exception: ", self.serial_port.in_waiting) pass def parse_readings(self, b): """ The Arduino script emits data in the format: [0]wind speed [1]wind direction [2]wind direction compass [3]temperature [4]barometer """ data = {} try: if "," in b: parts = b.split(",") # print("parsing: ", b, "parts =", parts) data = dict() data['outTemp'] = float(parts[0]) data['pressure'] = float(parts[1]) data['outHumidity'] = float(parts[2]) data['windSpeed'] = float(parts[3]) data['windDir'] = float(parts[4]) data['soilMoist1'] = float(parts[5]) data['soilTemp1'] = float(parts[6]) rain = parts[7].replace('\r\n', '').strip() data['rainTotal'] = float(rain) # pprint("Microbit driver: ", data) except Exception as e: logerr("Error parsing data: %s" % e) if DEBUG_READ: logdbg(data) return data @property def hardware_name(self): return "microbit" def genLoopPackets(self): ntries = 0 while ntries < self.max_tries: ntries += 1 try: packet = {'dateTime': int(time.time() + 0.5), 'usUnits': weewx.METRIC} serial_data = self.read_buffer() # read the buffer from the microbit climate data = self.parse_readings(serial_data) # parse the data packet.update(data) self._augment_packet(packet) ntries = 0 ''' # print the time between reads and the count for debugging for now self.read_counter += 1 time_since_last_read = time.time() - self.last_read_time print("%s seconds since last read" % time_since_last_read, self.read_counter) self.last_read_time = time.time() ''' yield packet if self.polling_interval: time.sleep(self.polling_interval) except (serial.serialutil.SerialException, weewx.WeeWxIOError) as e: logerr("Failed attempt %d of %d to get LOOP data: %s" % (ntries, self.max_tries, e)) time.sleep(self.retry_wait) else: msg = "Max retries (%d) exceeded for LOOP data" % self.max_tries logerr(msg) raise weewx.RetriesExceeded(msg) def _augment_packet(self, packet): # no wind direction when wind speed is zero if 'windSpeed' in packet and not packet['windSpeed']: packet['windDir'] = None # packet['rain'] = weewx.wxformulas.calculate_rain(packet.get('rain_total'), self.last_rain) # self.last_rain = packet.get('rain_total') class MicrobitConfEditor(weewx.drivers.AbstractConfEditor): @property def default_stanza(self): return """ [Microbit] # This section is for an Arduion Weather Station. # Serial port such as /dev/ttyACM0, /dev/ttyS0, /dev/ttyUSB0, or /dev/cuaU0 port = /dev/ttyACM0 # The driver to use: driver = user.microbit """ def prompt_for_settings(self): print("Specify the serial port on which the station is connected, for") print("example /dev/ttyUSB0 or /dev/ttyACM0.") port = self._prompt('port', '/dev/ttyACM0') return {'port': port} # define a main entry point for basic testing of the station without weewx # engine and service overhead. invoke this as follows from the weewx root dir: # # # To run on a standard apt-get install (unconfirmed, might ened to adjust path # PYTHONPATH=bin python /home/weewx/bin/user/Microbit.py # For setup.py instals: # PYTHONPATH=/home/weewx/bin python /home/weewx/bin/user/Microbit.py # if __name__ == '__main__': import optparse usage = """%prog [options] [--help]""" syslog.openlog('micro', syslog.LOG_PID | syslog.LOG_CONS) syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_DEBUG)) parser = optparse.OptionParser(usage=usage) parser.add_option('--version', dest='version', action='store_true', help='display driver version') parser.add_option('--port', dest='port', metavar='PORT', help='serial port to which the station is connected', default=DEFAULT_PORT) (options, args) = parser.parse_args() if options.version: print("micro driver version %s" % DRIVER_VERSION) exit(0) station = MicrobitDriver() for packet in station.genLoopPackets(): print(time.time(), packet)
