Gary, Many thanks for your reply. This is very helpful.
First issue fixed. units from Wunderground url as you say are in in/hr so I fixed that, i.e. /25.4. I have written my own driver based on one called socketlogge from here https://github.com/poblabs/weewx-socketlogger in my weewx.conf file i specify the driver and parameters. [W8681] # This section is for the W8681 wifi series of weather stations. # The driver to use: driver = weewx.drivers.w8681 [SocketLogger] # This section is for the SocketLogger driver # Station info: hardware = Generic intercept for wunderground urls # IP address, port number and timeout in seconds of the socket to connect to mode = sniff # driver mode either sniff of listen host_ip = XX.XX.XX.XX # in sniff mode ip of weather station else should be localhost for listen host_iface = eth1 # only required in sniff mode host_port = 80 # port to listen on or port to sniff timeout = 320 # timeout in seconds # this should be greater than the interval set on your pws # The driver to use driver = user.socketlogger I have attached the py script (still work in progress so use at own risk). Passes data to weewex with (for example) _packet['temp']. Not sure if this simply inserts data into the database or whether weewx actually "processes" the data. I am just trying to figure out how the rainrate is handled. Is weewx smart enough to know if I provide a rain rate of mm/hr every 5 minutes what the cumulative rainfall is? Just started running my script with a constant rainrate for 24hrs, will see what happens. So far the rain rate on the web interface is correct. Although the "Today's Rain" still says zero. Will let it run for a few days (we should have a total of 48mm tomorrow). Pete. -- 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 weewx-user+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
### Instruction for packet sniffing ## ## You need set your router to send copies of wunderground packets to the server running weewx ## I did this on my router that runs dd-wrt by running the following under Administration->Commands ## ## iptables -A PREROUTING -t mangle -s 192.168.1.13 -j ROUTE --gw 192.168.1.24 --tee ## ## this tells the router to make a copy of any packets sent from the PWS (first ip) to the ## machine running weewx (second ip) ## import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) import socket import syslog from time import gmtime, strftime import time import urlparse from scapy.all import IP, sniff from scapy.layers import http import string import weedb import weewx.drivers import weeutil.weeutil import weewx.wxformulas def logmsg(dst, msg): syslog.syslog(dst, 'SocketLogger: %s' % msg) def loginf(msg): logmsg(syslog.LOG_INFO, msg) def logerror(msg): logmsg(syslog.LOG_ERR, msg) def logdebug(msg): logmsg(syslog.LOG_DEBUG, msg) def loader(config_dict, engine): station = SocketLogger(**config_dict['SocketLogger']) return station def _fmt_bytes(data): return ' '.join(['%02x' % ord(x) for x in data]) def makeDic(): dictionary = { 'tempf' : 'outTemp', 'outtemp' : 'outTemp', 'humidity' : 'outHumidity', 'outhumi' : 'outHumidity', 'inhumi' : 'inHumidity', 'dewpoint' : 'dewpoint', 'dewptf' : 'dewpoint', 'winddir' : 'windDir', 'windspeed' : 'WindSpeed', 'windspeedmph' : 'windSpeed', 'windgustmph' : 'windGust', 'windgust' : 'windGust', 'windgustdir' : 'windGustDir', 'windchill' : 'windchill', 'windchillf' : 'windchill', #'rainin' : 'rainRate', #'rainrate' : 'rainRate', #'dailyrainin' : 'dayRain', #'dailyrain' : 'dayRain', #'yearlyrainin' : 'yearRain', #'monthlyrainin' : 'monthRain', #'monthlyrain' : 'monthlyrain', 'solarradiation' : 'radiation', 'UV' : 'UV', 'indoortempf' : 'inTemp', 'intemp' : 'InTemp', 'indoorhumidity' : 'inHumidity', 'baromin' : 'barometer', 'absbaromin' : 'pressure', 'absbaro' : 'pressure', 'relbaro' : 'barometer', 'soiltempf' : 'soilTemp1', 'soiltemp2f' : 'soilTemp2', 'soiltemp3f' : 'soilTemp3', 'soiltemp4f' : 'soilTemp4', 'soilmoisture' : 'soilMoist1', 'soilmoisture2' : 'soilMoist2', 'soilmoisture3' : 'soilMoist3', 'soilmoisture3' : 'soilMoist3', 'soilmoisture4' : 'soilMoist4', 'leafwetness' : 'leafWet1', 'leafwetness2' : 'leafWet2', 'lowbatt' : 'txBatteryStatus' } return dictionary class SocketLogger(weewx.drivers.AbstractDevice): #def archive_interval(self, config_dict): # archive_interval = config_dict['StdArchive'].get('archive_interval', 300) #config_dict.setdefault('StdWXCalculate', {}) #config_dict['StdWXCalculate'].setdefault('Calculatios', {}) #config_dict['StdWXCalculate']['Calculations']['rainRate'] = 'hardware' # return archive_interval SNAPLEN = 85535 PROMISCUOUS = 0 TIMEOUT_MS = 100 def __init__(self, **stn_dict): import pcap self.mode = stn_dict.get('mode') self.host_ip = stn_dict.get('host_ip') self.host_port = int(stn_dict.get('host_port')) self.timeout = float(stn_dict.get('timeout')) #self.archive_interval = config_dict['StdArchive'].get('archive_interval', 300) self.interval = 200 #self.archive_interval self.station_hardware = stn_dict.get('hardware') self.checkParams = [ "intemp", "tempf" ] self.lastrain = None self.port = None #self.openPort() if self.mode != 'sniff' and self.mode != 'listen': logerror("Socketlogger mode error " + self.mode + " is in valid. Should be \"sniff\" or \"listen\" ") raise weewx.WeeWxIOError() if self.mode == 'sniff': self.host_iface = stn_dict.get('host_iface') self.pcap_filter = "src host " + self.host_ip + " && " + "dst port " + str(self.host_port) self.packet_sniffer = pcap.pcapObject() #loginf("sniff iface %s" % self.host_iface) self.packet_sniffer.open_live( self.host_iface, self.SNAPLEN, self.PROMISCUOUS, self.TIMEOUT_MS) loginf("Socket logger in sniff mode") loginf("Sniffing on iface %s. Filter '%s'" %(self.host_iface, self.pcap_filter) ) self.packet_sniffer.setfilter(self.pcap_filter, 0, 0) self.running = False self.query_string = '' self.lastpacket = 'xx' self.newpacket = 'xx' self.last_data = '' elif self.mode == 'listen': loginf("Socket logger in listen mode") self.openPort() self.paramMap = makeDic() def run(self): self.running = True while self.running: self.packet_sniffer.dispatch(1, self.decode_ip_packet) if self.newpacket != self.lastpacket: self.lastpacket = self.newpacket yield self._process_message( self.newpacket ) #no point in collecting data more frequently than archive update interval time.sleep(self.interval) def openPort(self): try: loginf("Listenning on ip:port '%s:%s'" %(self.host_ip, self.host_port) ) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(self.timeout) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind((self.host_ip, self.host_port)) self.socket.listen(1) #loginf("Listening on ip:port " + str(self.host_ip) + ":" + str(self.host_port) ) #self.socket.connect( (self.host_ip, self.host_port) ) except (socket.error, socket.timeout, socket.herror), ex: logerror("Socket error while opening port %d to ethernet host %s." % (self.host_port, self.host_ip)) # Reraise as a weewx I/O error: raise weewx.WeeWxIOError(ex) except: logerror("Unable to connect to host %s on port %d." % (self.host_ip, self.host_port)) raise logdebug("Connected to host %s on port %d" % (self.host_ip, self.host_port)) self.port = self.socket.makefile() #def stop(self): # logdebug("stop sniff server") # self.running = False # self.packet_sniffer.close() # self.packet_sniffer = None def caught_error(self): a=1 def decode_ip_packet(self, _pktlen, data, _timestamp): if not data: loginf("no data") return logdebug("sniff: timestamp=%s pktlen=%s data=%s" % (_timestamp, _pktlen, _fmt_bytes(data))) if len(data) >= 15 and data[12:14] == '\x08\x00': header_len = ord(data[14]) & 0x0f idx = 4 * header_len + 34 if len(data) >= idx: _data = data[idx:] if _data == self.last_data: logdebug("sniff: dup ignore %s" % _fmt_bytes(_data)) if 'GET' in _data: logdebug("sniff: start %s" % _fmt_bytes(_data)) self.query_string = _data self.newpacket = self.query_string #loginf("sniff: final %s" % self.query_string) try: self.packet_sniffer.breakloop() except AttributeError: self.caught_error() #elif 'HTTP' in data: # and len(self.query_string): # loginf("sniff: final %s" % _fmt_bytes(self.query_string)) # data = urlparse.urlparse(self.query_string).query # logdebug("SNIFF: %s" % _obfuscate_passwords(data)) #Consumer.queue.put(data) # self.query_string = '' elif len(self.query_string): printable = set(string.printable) fdata = filter(lambda x: x in printable, _data) if fdata == _data: logdebug("sniff: append %s" % _fmt_bytes(_data)) self.query_string += _data else: logdebug("sniff: ignore %s" % _fmt_bytes(_data)) def hardware_name(self): return self.station_hardware #def closePort(self): # self.port.close() def check_rain(self, daily_rain_counter): # *** DO NOT use the &rainin= data! *** # Handle the rain accum by taking the &dailyrainin= reading ONLY. # Then submit those minor increments of daily rain to weewx. rain = 0.0 current_rain = float(daily_rain_counter) if self.lastrain is not None: if (current_rain >= self.lastrain): rain = float(current_rain) - float(self.lastrain) #loginf("Checking for new rain accumulation") #loginf(rain) self.lastrain = current_rain return rain #=============================================================================== # LOOP record decoding functions #=============================================================================== def genPackets(self): """ Generate measurement packets from the socket. """ while True: try: csock, caddr = self.socket.accept() _line = csock.recv(4096) #_line = self.port.readline(4096) #oginf(_line) except (socket.timeout, socket.error), ex: raise weewx.WeeWxIOError(ex) if _line == None: break if self.checkParams in _line: loginf("New line on socket, processing weather data.") csock.sendall("""HTTP/1.0 200 OK Content-Type: text/html <html> <head> <title>Success</title> </head> <body> success </body> </html> """) #csock.close() yield self._process_message(_line) else: #loginf("New line on socket, but did not start with 'outTemp='. Ignoring line.") pass def genLoopPackets(self): """ Generator function that continuously returns loop packets """ if self.mode == 'sniff': loginf("Socket logger now sniffing....") for _packet in self.run(): yield _packet elif self.mode == 'listen': for _packet in self.genPackets(): yield _packet def _process_message(self, message): _packet = {} #loginf("process: " + message) parsed = urlparse.urlparse(message) data = urlparse.parse_qsl(parsed.query) _packet['dateTime'] = int(time.time()) _packet['usUnits'] = weewx.US for x,y in data: #loginf( x + " " + y ) #convert rain inch to mm if 'rainin' in x : loginf( x + "---" + str( y ) ) _packet[ 'rainRate' ] = 2.0/25.4 #_packet[ 'rainRate' ] = float ( y ) / 25.4 #_packet['rain'] = self.check_rain( y ) #_packet['rain'] = float ( x['rainin'] ) / 25.4 # _packet[ self.paramMap[x] ] = float( y ) / 25.4 #else: if x in self.paramMap: #loginf( x + " " + self.paramMap[x] ) #loginf( x + " " + self.paramMap[x] + " " + str( y ) ) _packet[ self.paramMap[x] ] = float( y ) #loginf("Date packet read %s" %(time.time() ) ) loginf("Weather date packet read %s" %( strftime("%a, %d %b %Y %X +0000", gmtime()) ) ) return _packet