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

Reply via email to