def download_archive_interval(self): logdbg('downloading archive interval') data = self.get_data("http://weatherlink.com/webdl.php" "?timestamp=0&user=%s&pass=%s&action=headers" % (self.username, self.password)) if data is None: raise weewx.WeeWxIOError("download of archive interval failed") for line in data.splitlines(): if line.find('ArchiveInt=') >= 0: logdbg('found archive interval: %s' % line) return int(line[11:]) raise weewx.WeeWxIOError("cannot determine archive interval from %s" % data)
def get_data(url): try: request = Request(url) request.add_header('User-Agent', 'WeeWX/%s' % weewx.__version__) response = urlopen(request, timeout=4) except URLError as e: logerr("get_data(): Unable to open weather station %s or %s" % (url, e)) raise weewx.WeeWxIOError("get_data(): Socket error or timeout for weather station %s or %s" % (url, e)) except (socket.error, socket.timeout) as e: logerr("get_data(): Socket error or timeout for weather station %s or %s" % (url, e)) raise weewx.WeeWxIOError("get_data(): Socket error or timeout for weather station %s or %s" % (url, e)) if response.getcode() != 200: raise weewx.WeeWxIOError("get_data(): Bad response code returned: %d." % response.code) content_length = int(response.info().get('Content-Length')) return response.read(content_length).decode('utf-8')
def get_data(url): try: response = six.moves.urllib.request.urlopen(url) return response.read() except (socket.error, socket.timeout, six.moves.urllib.error.HTTPError, six.moves.urllib.error.URLError) as e: raise weewx.WeeWxIOError("get data failed: %s" % e)
def genLoopPackets(self): ntries = 0 while ntries < self.max_tries: ntries += 1 try: # Poll on poll_interval boundaries. if self.poll_interval != 0: time.sleep(self.time_to_next_poll()) data = IP100Station.get_data(self.station_url) log.debug("data: %s" % data) pkt = IP100Station.parse_data(data) log.debug("raw packet: %s" % pkt) ntries = 0 packet = {'dateTime': int(time.time() + 0.5)} if pkt['base_units'] == 'English': packet['usUnits'] = weewx.US else: packet['usUnits'] = weewx.METRICWX for k in self.sensor_map: if self.sensor_map[k] in pkt: packet[k] = pkt[self.sensor_map[k]] if 'day_rain_total' in packet: packet['rain'] = self._rain_total_to_delta( packet['day_rain_total'], self.previous_rain_total) self.previous_rain_total = packet['day_rain_total'] else: log.debug("no rain in packet: %s" % packet) log.debug("packet: %s" % packet) yield packet except weewx.WeeWxIOError as e: log.info("failed attempt %s of %s: %s" % (ntries, self.max_tries, e)) time.sleep(self.retry_wait) else: raise weewx.WeeWxIOError("max tries %s exceeded" % self.max_tries)
def _get_with_retries(self): for n in range(self.max_tries): try: return self.sensor.get_data() except (IOError, ValueError, TypeError) as e: loginf("failed attempt %s of %s: %s" % (n + 1, self.max_tries, e)) time.sleep(self.retry_wait) else: raise weewx.WeeWxIOError("%s: max tries %s exceeded" % (method, self.max_tries))
def __init__(self, **stn_dict): loginf('driver version is %s' % DRIVER_VERSION) self.model = stn_dict.get('model', 'MS-120') loginf("model is %s" % self.model) port = stn_dict.get('port', Tracer.DEFAULT_PORT) loginf("port is %s" % port) baud_rate = int(stn_dict.get('baud_rate', Tracer.DEFAULT_BAUD_RATE)) timeout = int(stn_dict.get('timeout', Tracer.DEFAULT_TIMEOUT)) self.poll_interval = int(stn_dict.get('poll_interval', 10)) loginf("poll interval is %s" % self.poll_interval) self.sensor_map = dict(TracerDriver.DEFAULT_MAP) if 'sensor_map' in stn_dict: self.sensor_map.update(stn_dict['sensor_map']) loginf("sensor map: %s" % self.sensor_map) self.max_tries = int(stn_dict.get('max_tries', 3)) self.retry_wait = int(stn_dict.get('retry_wait', 5)) self.station = Tracer(port, baud_rate, timeout) if not self.station.connect(): raise weewx.WeeWxIOError("cannot connect to device") loginf('device info: %s' % self.station.get_info())
def parse_data(data): """Parse the XML data which is a flat non-hierarchical record and return a two-level dictionary hierarchy where each key is the field group and associated with that, a dictionary with the fields and values associated with that group.""" import re pkt_grp = dict() # If closing tag is truncated or has excess junk like null bytes, # fix before parsing. if data.startswith('<oriondata') and not data.endswith('</oriondata>'): data = re.sub('</ori(ondata)?.*$','</oriondata>', data) logerr("parse_data(): attempted to correct truncated data: %s" % data[-19:-1]) try: elements = ElementTree.fromstring(data) if elements.tag == 'oriondata' and elements[0].tag == 'meas': for child in elements: name = child.attrib['name'] # Ensure the correct tag and attribute is one to be recorded if child.tag == 'meas' and name in ColumbiaMicroServerStation.XML_INPUT_ELEMENTS: # Get the associated packet group for this field pkt_type = ColumbiaMicroServerStation.XML_INPUT_ELEMENTS[name] # Initialize a new dictionary for a packet group if not pkt_type in pkt_grp: pkt_grp[pkt_type] = dict() # If the field is in the list to use for the unit type, # save the unit type as the field 'base_units'. if name in ColumbiaMicroServerStation.XML_INPUT_UNIT_ELEMENTS: # If the packet type is 'generic' then it's a unit type that's # neither US or metric such as degrees for wind direction. if pkt_type == 'generic': pkt_grp[pkt_type]['base_units'] = 'generic' else: pkt_grp[pkt_type]['base_units'] = child.attrib['unit'] # Store the field and value in the dictionary for the associated packet type. pkt_grp[pkt_type][name] = float(child.text) else: raise ElementTree.ParseError("invalid XML file. Missing <oriondata> and/or <meas/> tags detected.") except ElementTree.ParseError as e: logerr("ElementTree ParseError: %s for data: %s" % (e, data)) raise weewx.WeeWxIOError(e) return pkt_grp
def genLoopPackets(self): while True: try: buf = self.station.read() if buf: pkt = Station.decode(buf) if buf[0] in [0xd3, 0xd4, 0xd5, 0xd6, 0xdb, 0xdc]: # send ack for most data packets # FIXME: what is last number in the ACK? # observed: 0x00 0x20 0xc1 0xc7 0xa0 0x99 cmd = [ 0x41, 0x43, 0x4b, buf[0], buf[7], _lo(self.last_record) ] self.station.write(cmd) packet = self.convert_loop(pkt) self.cached.update(packet) yield self.cached if time.time() - self.last_a6 > self.heartbeat: logdbg("request station status: %s (%02x)" % (self.last_record, _lo(self.last_record))) cmd = [0xa6, 0x91, 0xca, 0x45, 0x52, _lo(self.last_record)] self.station.write(cmd) self.last_a6 = time.time() if self.last_7x == 0: # FIXME: what are the 72/73 messages? # observed: # 73 e5 0a 26 0e c1 # 73 e5 0a 26 88 8b # 72 a9 c1 60 52 00 # cmd = [0x72, 0xa9, 0xc1, 0x60, 0x52, 0x00] cmd = [0x73, 0xe5, 0x0a, 0x26, 0x88, 0x8b] # cmd = [0x73, 0xe5, 0x0a, 0x26, 0x0e, 0xc1] self.station.write(cmd) self.last_7x = time.time() except usb.USBError, e: if not e.args[0].find('No data available'): raise weewx.WeeWxIOError(e) except (WrongLength, BadChecksum), e: loginf(e)
pkt['pm2_5'] = pm2_5 pkt['pm10_0'] = pm10_0 yield pkt if self.poll_interval: time.sleep(self.poll_interval) def _get_with_retries(self): for n in range(self.max_tries): try: return self.sensor.get_data() except (IOError, ValueError, TypeError), e: loginf("failed attempt %s of %s: %s" % (n + 1, self.max_tries, e)) time.sleep(self.retry_wait) else: raise weewx.WeeWxIOError("%s: max tries %s exceeded" % (method, self.max_tries)) def _fmt(x): return ' '.join(["%0.2X" % ord(c) for c in x]) class SDS011(object): DEFAULT_PORT = '/dev/ttyUSB0' DEFAULT_BAUDRATE = 9600 DEFAULT_TIMEOUT = 3.0 # seconds CMD_MODE = 2 CMD_QUERY_DATA = 4 CMD_DEVICE_ID = 5 CMD_SLEEP = 6 CMD_FIRMWARE = 7
def get_data(url): try: response = urllib2.urlopen(url) return response.read() except (socket.error, socket.timeout, urllib2.HTTPError), e: raise weewx.WeeWxIOError("get data failed: %s" % e)
if pkt['base_units'] == 'English': packet['usUnits'] = weewx.US else: packet['usUnits'] = weewx.METRICWX for k in self.sensor_map: if self.sensor_map[k] in pkt: packet[k] = pkt[self.sensor_map[k]] yield packet if self.poll_interval: time.sleep(self.poll_interval) except weewx.WeeWxIOError, e: loginf("failed attempt %s of %s: %s" % (ntries, self.max_tries, e)) time.sleep(self.retry_wait) else: raise weewx.WeeWxIOError("max tries %s exceeded" % self.max_tries) class IP100Station(object): @staticmethod def get_data(url): try: response = urllib2.urlopen(url) return response.read() except (socket.error, socket.timeout, urllib2.HTTPError), e: raise weewx.WeeWxIOError("get data failed: %s" % e) @staticmethod def parse_data(data): pkt = dict() try:
def genStartupRecords(self, since_ts): loginf("reading records since %s" % timestamp_to_string(since_ts)) hbuf = None last_ts = None cnt = 0 while True: try: buf = self.station.read() if buf: if buf[0] == 0xd2: hbuf = buf buf = None elif buf[0] == 0x7f and hbuf is not None: # FIXME: need better indicator of second half history buf = hbuf + buf hbuf = None if buf and buf[0] == 0xd2: self.last_record = Station.get_record_index(buf) ts = Station._extract_ts(buf[4:9]) if ts is not None and ts > since_ts: keep = True if last_ts is not None else False pkt = Station.decode(buf) packet = self.convert_historical(pkt, ts, last_ts) last_ts = ts if keep: logdbg("historical record: %s" % packet) cnt += 1 yield packet if buf and buf[0] == 0x57: idx = Station.get_latest_index(buf) msg = "count=%s last_index=%s latest_index=%s" % ( cnt, self.last_record, idx) if self.last_record + 1 >= idx: loginf("catchup complete: %s" % msg) break loginf("catchup in progress: %s" % msg) if buf and buf[0] == 0x41 and buf[3] == 0x65: nxtrec = Station.get_next_index(self.last_record) logdbg("request records starting with %s" % nxtrec) cmd = [0xcd, 0x18, 0x30, 0x62, _hi(nxtrec), _lo(nxtrec)] self.station.write(cmd) if time.time() - self.last_a6 > self.heartbeat: logdbg("request station status: %s (%02x)" % (self.last_record, _lo(self.last_record))) cmd = [0xa6, 0x91, 0xca, 0x45, 0x52, _lo(self.last_record)] self.station.write(cmd) self.last_a6 = time.time() if self.last_7x == 0: # FIXME: what does 72/73 do? cmd = [0x73, 0xe5, 0x0a, 0x26, 0x88, 0x8b] self.station.write(cmd) self.last_7x = time.time() if time.time() - self.last_65 > self.history_retry: logdbg("initiate record request: %s (%02x)" % (self.last_record, _lo(self.last_record))) cmd = [0x65, 0x19, 0xe5, 0x04, 0x52, _lo(self.last_record)] self.station.write(cmd) self.last_65 = time.time() except usb.USBError, e: if not e.args[0].find('No data available'): raise weewx.WeeWxIOError(e) except (WrongLength, BadChecksum), e: loginf(e)