From a0ed8ec21530a69c89c2ae24a03e68dfa63ed7c2 Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Wed, 6 Apr 2016 02:28:02 -0400 Subject: [PATCH 01/11] Make some changes requested by someone else Bump driver version to 0.25 Import socket globally, as it is part of the Python standard library Steps towards PEP8 compliance: double spacing between top-level functions and classes. Add timeout, max_retries, and retry_interval fields to StationInet class. Retry TCP/IP connection if connection fails. If the connection fails more than a certain amount of times, then error out. --- bin/weewx/drivers/ws1.py | 63 +++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index 153372ae..5106edf0 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -16,16 +16,18 @@ Thanks to Jay Nugent (WB8TKL) and KRK6 for weather-2.kr6k-V2.1 from __future__ import with_statement import syslog import time +import socket import weewx.drivers DRIVER_NAME = 'WS1' -DRIVER_VERSION = '0.24' +DRIVER_VERSION = '0.25' def loader(config_dict, _): return WS1Driver(**config_dict[DRIVER_NAME]) + def confeditor_loader(): return WS1ConfEditor() @@ -44,15 +46,19 @@ DEBUG_READ = 0 def logmsg(level, msg): syslog.syslog(level, 'ws1: %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 WS1Driver(weewx.drivers.AbstractDevice): """weewx driver that communicates with an ADS-WS1 station @@ -60,7 +66,7 @@ class WS1Driver(weewx.drivers.AbstractDevice): [Required. Default is serial] port - Serial port or network address. - [Required. Default is /dev/ttyS0 for serial, and 192.168.36.25:3000 for TCP] + [Required. Default is /dev/ttyS0 for serial, and 192.168.36.25:3000 for TCP/IP] max_tries - how often to retry serial communication before giving up. [Optional. Default is 5] @@ -95,7 +101,8 @@ class WS1Driver(weewx.drivers.AbstractDevice): DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) if con_mode == 'tcp' or con_mode == 'udp': - self.station = StationInet(self.port, con_mode, timeout=timeout) + self.station = StationInet(self.port, con_mode, timeout, max_tries, + retry_wait) else: self.station = StationSerial(self.port, timeout=timeout) self.station.open() @@ -176,7 +183,7 @@ class StationData(object): # FIXME: for ws1 is the pressure reading 'pressure' or 'barometer'? buf = raw[2:] data = dict() - data['windSpeed'] = StationData._decode(buf[0:4], 0.1 * MILE_PER_KM) # mph + data['windSpeed'] = StationData._decode(buf[0:4], 0.1 * MILE_PER_KM) # mph data['windDir'] = StationData._decode(buf[6:8], 1.411764) # compass deg data['outTemp'] = StationData._decode(buf[8:12], 0.1, True) # degree_F data['long_term_rain'] = StationData._decode(buf[12:16], 0.01) # inch @@ -272,11 +279,22 @@ class StationSerial(object): class StationInet(object): - def __init__(self, addr, protocol='tcp', timeout=3): - import socket + def __init__(self, addr, protocol='tcp', timeout=3, max_retries=5, + retry_interval=10): ip_addr = None ip_port = None - self.protocol = protocol + + if protocol in ['tcp', 'udp']: self.protocol = protocol + else: self.protocol = 'tcp' + + if isinstance(max_retries, int): self.max_retries = max_retries + else: self.max_retries = 5 + + if isinstance(retry_interval, int): + self.retry_interval = retry_interval + else: + self.retry_interval = 10 + if addr.find(':') != -1: self.conn_info = addr.split(':') try: @@ -288,6 +306,7 @@ class StationInet(object): ip_addr = addr ip_port = DEFAULT_TCP_PORT self.conn_info = (ip_addr, ip_port) + try: if self.protocol == 'tcp': self.net_socket = socket.socket( @@ -298,21 +317,32 @@ class StationInet(object): except (socket.error, socket.herror), ex: logerr("Cannot create socket for some reason: %s" % ex) raise weewx.WeeWxIOError(ex) - self.net_socket.settimeout(timeout) + + if isinstance(timeout, int): self.net_socket.settimeout(timeout) + else: self.net_socket.settimeout(3) self.rec_start = False def open(self): - import socket logdbg("Connecting to %s:%d." % (self.conn_info[0], self.conn_info[1])) - try: - self.net_socket.connect(self.conn_info) - except (socket.error, socket.timeout, socket.herror), ex: - logerr("Cannot connect to %s:%d for some reason: %s" % ( - self.conn_info[0], self.conn_info[1], ex)) - raise weewx.WeeWxIOError(ex) + exstr = '' + + for conn_attempt in range(self.max_retries): + try: + if conn_attempt > 1: + logerr("Retrying connection...") + self.net_socket.connect(self.conn_info) + break + except (socket.error, socket.timeout, socket.herror), ex: + logerr("Cannot connect to %s:%d for some reason: %s." % ( + self.conn_info[0], self.conn_info[1], ex)) + logerr("Will retry in %d seconds..." % self.retry_interval) + exstr = '%s' % ex + time.sleep(self.retry_interval) + else: + logerr("Max retries (%d) exceeded for connection." % self.max_retries) + raise weewx.WeeWxIOError(exstr) def close(self): - import socket logdbg("Closing connection to %s:%d." % (self.conn_info[0], self.conn_info[1])) try: @@ -323,7 +353,6 @@ class StationInet(object): raise weewx.WeeWxIOError(ex) def get_readings(self): - import socket if self.rec_start is not True: # Find the record start if DEBUG_READ >= 1: From e17e01da2bd394741ba0ee2d3be813b4215899ca Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Fri, 8 Apr 2016 00:03:26 -0400 Subject: [PATCH 02/11] Remove unnecessary type/bounds checks. --- bin/weewx/drivers/ws1.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index 5106edf0..e52771ca 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -284,17 +284,6 @@ class StationInet(object): ip_addr = None ip_port = None - if protocol in ['tcp', 'udp']: self.protocol = protocol - else: self.protocol = 'tcp' - - if isinstance(max_retries, int): self.max_retries = max_retries - else: self.max_retries = 5 - - if isinstance(retry_interval, int): - self.retry_interval = retry_interval - else: - self.retry_interval = 10 - if addr.find(':') != -1: self.conn_info = addr.split(':') try: From 7e8e1d948e3071e25692f01bf698bf8d3ac6a87f Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Fri, 8 Apr 2016 03:29:26 -0400 Subject: [PATCH 03/11] Fix all errors that occur when trying to initialize the driver. Most of the errors were references to nonexistent variables. I've finally got to testing this driver, and fixed these errors in the process. --- bin/weewx/drivers/ws1.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index e52771ca..35a295c7 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -66,7 +66,8 @@ class WS1Driver(weewx.drivers.AbstractDevice): [Required. Default is serial] port - Serial port or network address. - [Required. Default is /dev/ttyS0 for serial, and 192.168.36.25:3000 for TCP/IP] + [Required. Default is /dev/ttyS0 for serial, + and 192.168.36.25:3000 for TCP/IP] max_tries - how often to retry serial communication before giving up. [Optional. Default is 5] @@ -101,8 +102,8 @@ class WS1Driver(weewx.drivers.AbstractDevice): DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) if con_mode == 'tcp' or con_mode == 'udp': - self.station = StationInet(self.port, con_mode, timeout, max_tries, - retry_wait) + self.station = StationInet(self.port, con_mode, timeout, + self.max_tries, self.retry_wait) else: self.station = StationSerial(self.port, timeout=timeout) self.station.open() @@ -284,6 +285,9 @@ class StationInet(object): ip_addr = None ip_port = None + self.max_retries = max_retries + self.retry_interval = retry_interval + if addr.find(':') != -1: self.conn_info = addr.split(':') try: @@ -297,10 +301,10 @@ class StationInet(object): self.conn_info = (ip_addr, ip_port) try: - if self.protocol == 'tcp': + if protocol == 'tcp': self.net_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM) - elif self.protocol == 'udp': + elif protocol == 'udp': self.net_socket = socket.socket( socket.AF_INET, socket.SOCK_DGRAM) except (socket.error, socket.herror), ex: From 1b2ed87df2cd6b278f096e94c9592fd3a841d38c Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Sat, 9 Apr 2016 22:09:45 -0400 Subject: [PATCH 04/11] Implement most suggestions by Tom Keffer and Matthew Wall Rename StationInet to StationSocket. Change the logging level of some error/debug messages. Don't import socket globally. --- bin/weewx/drivers/ws1.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index 35a295c7..ee6ed3f8 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -16,7 +16,6 @@ Thanks to Jay Nugent (WB8TKL) and KRK6 for weather-2.kr6k-V2.1 from __future__ import with_statement import syslog import time -import socket import weewx.drivers @@ -102,8 +101,8 @@ class WS1Driver(weewx.drivers.AbstractDevice): DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) if con_mode == 'tcp' or con_mode == 'udp': - self.station = StationInet(self.port, con_mode, timeout, - self.max_tries, self.retry_wait) + self.station = StationSocket(self.port, con_mode, timeout, + self.max_tries, self.retry_wait) else: self.station = StationSerial(self.port, timeout=timeout) self.station.open() @@ -279,9 +278,11 @@ class StationSerial(object): # =========================================================================== # -class StationInet(object): +class StationSocket(object): def __init__(self, addr, protocol='tcp', timeout=3, max_retries=5, retry_interval=10): + import socket + ip_addr = None ip_port = None @@ -316,26 +317,32 @@ class StationInet(object): self.rec_start = False def open(self): + import socket + logdbg("Connecting to %s:%d." % (self.conn_info[0], self.conn_info[1])) exstr = '' for conn_attempt in range(self.max_retries): try: if conn_attempt > 1: - logerr("Retrying connection...") + logdbg("Retrying connection...") self.net_socket.connect(self.conn_info) break except (socket.error, socket.timeout, socket.herror), ex: - logerr("Cannot connect to %s:%d for some reason: %s." % ( - self.conn_info[0], self.conn_info[1], ex)) - logerr("Will retry in %d seconds..." % self.retry_interval) + logerr("Cannot connect to %s:%d for some reason: %s. " + "%d tries left." % ( + self.conn_info[0], self.conn_info[1], ex)) + logdbg("Will retry in %d seconds..." % self.retry_interval) exstr = '%s' % ex time.sleep(self.retry_interval) else: - logerr("Max retries (%d) exceeded for connection." % self.max_retries) + logerr("Max retries (%d) exceeded for connection." % + self.max_retries) raise weewx.WeeWxIOError(exstr) def close(self): + import socket + logdbg("Closing connection to %s:%d." % (self.conn_info[0], self.conn_info[1])) try: @@ -346,6 +353,7 @@ class StationInet(object): raise weewx.WeeWxIOError(ex) def get_readings(self): + import socket if self.rec_start is not True: # Find the record start if DEBUG_READ >= 1: @@ -408,15 +416,7 @@ class StationInet(object): raise weewx.WeeWxIOError(ex) if DEBUG_READ >= 2: logdbg("buf: %s" % buf) - # This code assumes CRLF will be transmitted at the end of each record, - # which may not always be the case. See Matthew Wall's comment on - # GitHub here: - # https://github.com/weewx/weewx/pull/86#issuecomment-166716509 - # try: - # self.net_socket.recv(2, socket.MSG_WAITALL) # CRLF - # except (socket.error, socket.timeout), ex: - # raise weewx.WeeWxIOError(ex) buf.strip() return buf @@ -428,7 +428,7 @@ class StationInet(object): StationData.validate_string(buf) return buf except (weewx.WeeWxIOError), e: - loginf("Failed to get data for some reason: %s" % e) + logdbg("Failed to get data for some reason: %s" % e) self.rec_start = False # NOTE: WeeWx IO Errors may not always occur because of From adb8abed843ced39e7bef6ff9fbee7e66b84b51e Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Sat, 9 Apr 2016 22:10:54 -0400 Subject: [PATCH 05/11] Remove another unnecessary type check. --- bin/weewx/drivers/ws1.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index ee6ed3f8..5d583cc5 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -312,8 +312,7 @@ class StationSocket(object): logerr("Cannot create socket for some reason: %s" % ex) raise weewx.WeeWxIOError(ex) - if isinstance(timeout, int): self.net_socket.settimeout(timeout) - else: self.net_socket.settimeout(3) + self.net_socket.settimeout(timeout) self.rec_start = False def open(self): From 0023ee619a764464c4081b5c00ff35d670b01ff0 Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Sat, 9 Apr 2016 22:37:37 -0400 Subject: [PATCH 06/11] Validate the user's settings in the WS1Driver constructor. --- bin/weewx/drivers/ws1.py | 45 ++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index 5d583cc5..60bf8d65 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -83,22 +83,55 @@ class WS1Driver(weewx.drivers.AbstractDevice): [Optional. Default is 0] """ def __init__(self, **stn_dict): + import re + + REGEX_IP_ADDR = re.compile(r'^(?:\d{1,3}\.){3}\d{1,3}:\d{2,5}$') + REGEX_SER_PORT = re.compile(r'^(?:COM\d+|CNC\w\d+|/dev/ttyS\d+)$') + + valerrstr = 'Invalid value for %s! Using %s instead.' loginf('driver version is %s' % DRIVER_VERSION) con_mode = stn_dict.get('mode', 'serial').lower() if con_mode == 'tcp' or con_mode == 'udp': - self.port = stn_dict.get( + port = stn_dict.get( 'port', '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT)) + if REGEX_IP_ADDR.match(port): + self.port = port + else: + # self.port = '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT) + # logdbg(valerrstr % ('port', self.port)) + raise ValueError("Invalid IP:Port address!" % con_mode) else: - self.port = stn_dict.get('port', DEFAULT_SER_PORT) + port = stn_dict.get('port', DEFAULT_SER_PORT) + if REGEX_SER_PORT.match(port): + self.port = port + else: + raise ValueError("Invalid serial port!") + + try: + self.max_tries = int(stn_dict.get('max_tries', 5)) + except ValueError, ex: + logdbg(valerrstr % ('max_tries', 5)) + + try: + self.retry_wait = int(stn_dict.get('retry_wait', 10)) + except ValueError, ex: + logdbg(valerrstr % ('retry_wait', 10)) + + try: + timeout = int(stn_dict.get('timeout', 3)) + except ValueError, ex: + logdbg(valerrstr % ('timeout', 3)) - self.max_tries = int(stn_dict.get('max_tries', 5)) - self.retry_wait = int(stn_dict.get('retry_wait', 10)) self.last_rain = None - timeout = int(stn_dict.get('timeout', 3)) + loginf('using %s port %s' % (con_mode, self.port)) + global DEBUG_READ - DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) + try: + DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) + except ValueError, ex: + logdbg(valerrstr % ('debug_read', DEBUG_READ)) if con_mode == 'tcp' or con_mode == 'udp': self.station = StationSocket(self.port, con_mode, timeout, From 956ed716bdb3eff292a99c4e05e569e71f260cbd Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Sat, 9 Apr 2016 23:19:54 -0400 Subject: [PATCH 07/11] Remove exstr, and change a few log levels again. --- bin/weewx/drivers/ws1.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index 60bf8d65..c00197b2 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -111,17 +111,17 @@ class WS1Driver(weewx.drivers.AbstractDevice): try: self.max_tries = int(stn_dict.get('max_tries', 5)) except ValueError, ex: - logdbg(valerrstr % ('max_tries', 5)) + loginf(valerrstr % ('max_tries', 5)) try: self.retry_wait = int(stn_dict.get('retry_wait', 10)) except ValueError, ex: - logdbg(valerrstr % ('retry_wait', 10)) + loginf(valerrstr % ('retry_wait', 10)) try: timeout = int(stn_dict.get('timeout', 3)) except ValueError, ex: - logdbg(valerrstr % ('timeout', 3)) + loginf(valerrstr % ('timeout', 3)) self.last_rain = None @@ -131,7 +131,7 @@ class WS1Driver(weewx.drivers.AbstractDevice): try: DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) except ValueError, ex: - logdbg(valerrstr % ('debug_read', DEBUG_READ)) + loginf(valerrstr % ('debug_read', DEBUG_READ)) if con_mode == 'tcp' or con_mode == 'udp': self.station = StationSocket(self.port, con_mode, timeout, @@ -352,7 +352,6 @@ class StationSocket(object): import socket logdbg("Connecting to %s:%d." % (self.conn_info[0], self.conn_info[1])) - exstr = '' for conn_attempt in range(self.max_retries): try: @@ -363,14 +362,14 @@ class StationSocket(object): except (socket.error, socket.timeout, socket.herror), ex: logerr("Cannot connect to %s:%d for some reason: %s. " "%d tries left." % ( - self.conn_info[0], self.conn_info[1], ex)) + self.conn_info[0], self.conn_info[1], ex, + self.max_retries - (conn_attempt + 1))) logdbg("Will retry in %d seconds..." % self.retry_interval) - exstr = '%s' % ex time.sleep(self.retry_interval) else: logerr("Max retries (%d) exceeded for connection." % self.max_retries) - raise weewx.WeeWxIOError(exstr) + raise weewx.WeeWxIOError() def close(self): import socket From a5cf14e7b7ba00f3212eb368fb22590af853e8cc Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Mon, 11 Apr 2016 15:14:30 -0400 Subject: [PATCH 08/11] Add extra validation to WS1Driver constructor. --- bin/weewx/drivers/ws1.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index c00197b2..e7092df1 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -85,7 +85,9 @@ class WS1Driver(weewx.drivers.AbstractDevice): def __init__(self, **stn_dict): import re - REGEX_IP_ADDR = re.compile(r'^(?:\d{1,3}\.){3}\d{1,3}:\d{2,5}$') + REGEX_IP_ADDR = re.compile( + r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(:\d{1,5})?$') + REGEX_SER_PORT = re.compile(r'^(?:COM\d+|CNC\w\d+|/dev/ttyS\d+)$') valerrstr = 'Invalid value for %s! Using %s instead.' @@ -95,7 +97,14 @@ class WS1Driver(weewx.drivers.AbstractDevice): if con_mode == 'tcp' or con_mode == 'udp': port = stn_dict.get( 'port', '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT)) - if REGEX_IP_ADDR.match(port): + port_match = REGEX_IP_ADDR.match(port) + if port_match: + ip_addr = port_match.groups() + if not all([0 <= int(x) <= 255 for x in ip_addr[:4]]): + raise ValueError("Invalid byte in IP:Port address!") + if not 1 <= int(ip_addr[4][1:]) <= 65535: + raise ValueError("Invalid port number in IP:Port address!") + self.port = port else: # self.port = '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT) From 83d419e083ab75b56ea4a380567b5b17edd30778 Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Mon, 11 Apr 2016 18:56:30 -0400 Subject: [PATCH 09/11] Allow user to omit the port number. If the user decides to omit the port number, the default port (3000) will be used. --- bin/weewx/drivers/ws1.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index e7092df1..2f2c9908 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -100,12 +100,17 @@ class WS1Driver(weewx.drivers.AbstractDevice): port_match = REGEX_IP_ADDR.match(port) if port_match: ip_addr = port_match.groups() + if not all([0 <= int(x) <= 255 for x in ip_addr[:4]]): raise ValueError("Invalid byte in IP:Port address!") - if not 1 <= int(ip_addr[4][1:]) <= 65535: - raise ValueError("Invalid port number in IP:Port address!") + if ip_addr[4] is not None: + if not 1 <= int(ip_addr[4][1:]) <= 65535: + raise ValueError( + "Invalid port number in IP:Port address!") + self.port = port + else: + self.port = "%s:%d" % (port, DEFAULT_TCP_PORT) - self.port = port else: # self.port = '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT) # logdbg(valerrstr % ('port', self.port)) From 546a8b6558b652c840ffa24b6f1070c572a38eda Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Mon, 18 Apr 2016 23:48:48 -0400 Subject: [PATCH 10/11] Remove unnecessary validation code. --- bin/weewx/drivers/ws1.py | 63 +++++----------------------------------- 1 file changed, 8 insertions(+), 55 deletions(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index 2f2c9908..be29cb22 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -83,75 +83,31 @@ class WS1Driver(weewx.drivers.AbstractDevice): [Optional. Default is 0] """ def __init__(self, **stn_dict): - import re - - REGEX_IP_ADDR = re.compile( - r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(:\d{1,5})?$') - - REGEX_SER_PORT = re.compile(r'^(?:COM\d+|CNC\w\d+|/dev/ttyS\d+)$') - - valerrstr = 'Invalid value for %s! Using %s instead.' loginf('driver version is %s' % DRIVER_VERSION) con_mode = stn_dict.get('mode', 'serial').lower() if con_mode == 'tcp' or con_mode == 'udp': port = stn_dict.get( 'port', '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT)) - port_match = REGEX_IP_ADDR.match(port) - if port_match: - ip_addr = port_match.groups() - - if not all([0 <= int(x) <= 255 for x in ip_addr[:4]]): - raise ValueError("Invalid byte in IP:Port address!") - if ip_addr[4] is not None: - if not 1 <= int(ip_addr[4][1:]) <= 65535: - raise ValueError( - "Invalid port number in IP:Port address!") - self.port = port - else: - self.port = "%s:%d" % (port, DEFAULT_TCP_PORT) - - else: - # self.port = '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT) - # logdbg(valerrstr % ('port', self.port)) - raise ValueError("Invalid IP:Port address!" % con_mode) else: port = stn_dict.get('port', DEFAULT_SER_PORT) - if REGEX_SER_PORT.match(port): - self.port = port - else: - raise ValueError("Invalid serial port!") - try: - self.max_tries = int(stn_dict.get('max_tries', 5)) - except ValueError, ex: - loginf(valerrstr % ('max_tries', 5)) - - try: - self.retry_wait = int(stn_dict.get('retry_wait', 10)) - except ValueError, ex: - loginf(valerrstr % ('retry_wait', 10)) - - try: - timeout = int(stn_dict.get('timeout', 3)) - except ValueError, ex: - loginf(valerrstr % ('timeout', 3)) + self.max_tries = int(stn_dict.get('max_tries', 5)) + self.retry_wait = int(stn_dict.get('retry_wait', 10)) + timeout = int(stn_dict.get('timeout', 3)) self.last_rain = None - loginf('using %s port %s' % (con_mode, self.port)) + loginf('using %s port %s' % (con_mode, port)) global DEBUG_READ - try: - DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) - except ValueError, ex: - loginf(valerrstr % ('debug_read', DEBUG_READ)) + DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ)) if con_mode == 'tcp' or con_mode == 'udp': - self.station = StationSocket(self.port, con_mode, timeout, + self.station = StationSocket(port, con_mode, timeout, self.max_tries, self.retry_wait) else: - self.station = StationSerial(self.port, timeout=timeout) + self.station = StationSerial(port, timeout=timeout) self.station.open() def closePort(self): @@ -338,10 +294,7 @@ class StationSocket(object): if addr.find(':') != -1: self.conn_info = addr.split(':') - try: - self.conn_info[1] = int(self.conn_info[1], 10) - except TypeError: - self.conn_info[1] = DEFAULT_TCP_PORT + self.conn_info[1] = int(self.conn_info[1], 10) self.conn_info = tuple(self.conn_info) else: ip_addr = addr From 46f4ee6c401d8a3f1cf33da449add98bd236e64d Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Tue, 19 Apr 2016 21:00:38 -0400 Subject: [PATCH 11/11] Ensure given connection mode is valid. The valid connection mode choices are 'tcp', 'udp', or 'serial'. --- bin/weewx/drivers/ws1.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/weewx/drivers/ws1.py b/bin/weewx/drivers/ws1.py index be29cb22..06ab8744 100644 --- a/bin/weewx/drivers/ws1.py +++ b/bin/weewx/drivers/ws1.py @@ -89,8 +89,10 @@ class WS1Driver(weewx.drivers.AbstractDevice): if con_mode == 'tcp' or con_mode == 'udp': port = stn_dict.get( 'port', '%s:%d' % (DEFAULT_TCP_ADDR, DEFAULT_TCP_PORT)) - else: + elif con_mode == 'serial': port = stn_dict.get('port', DEFAULT_SER_PORT) + else: + raise ValueError("Invalid driver connection mode %s!" % con_mode) self.max_tries = int(stn_dict.get('max_tries', 5)) self.retry_wait = int(stn_dict.get('retry_wait', 10))