def perform(self): url = 'https://api.ambientweather.net/v1/devices/' + str( self.params["macAddress"]) parameterList = [("apiKey", str(self.params["apiKey"])), ("applicationKey", str(self.params["applicationKey"])), ("limit", "1")] log.info('Getting data from {0}'.format(str(url))) data = self.openURL(url, parameterList) if data is None: self.lastKnownError = "Error: No data received from server" log.error(self.lastKnownError) return station = json.loads(data.read()) for entry in station: dateutc = entry["dateutc"] / 1000 # from milliseconds if 'tempf' in entry: temp = convertFahrenheitToCelsius(entry["tempf"]) self.addValue(RMParser.dataType.TEMPERATURE, dateutc, temp, False) if 'humidity' in entry: self.addValue(RMParser.dataType.RH, dateutc, entry["humidity"], False) if 'windspeedmph' in entry: windspeed = entry["windspeedmph"] * 0.44704 # to meters/sec self.addValue(RMParser.dataType.WIND, dateutc, windspeed, False) if 'solarradiation' in entry: solarrad = convertRadiationFromWattsToMegaJoules( entry["solarradiation"]) self.addValue(RMParser.dataType.SOLARRADIATION, dateutc, solarrad, False) if 'dailyrainin' in entry: rain = convertInchesToMM(entry["dailyrainin"]) self.addValue(RMParser.dataType.RAIN, dateutc, rain, False) if 'baromrelin' in entry: pressure = entry["baromrelin"] * 3.38639 # to kPa self.addValue(RMParser.dataType.PRESSURE, dateutc, pressure, False) if 'dewPoint' in entry: dewpoint = convertFahrenheitToCelsius(entry["dewPoint"]) self.addValue(RMParser.dataType.DEWPOINT, dateutc, dewpoint, False) return True
def parsePacket(self, raw_data): self.lastKnownError = "" if raw_data is None or len(raw_data) < 99: self.lastKnownError = "Invalid data response" return False timestamp = rmCurrentTimestamp() if self.parserDebug: hex_string = binascii.hexlify(raw_data).decode('utf-8') log.info("Raw Data LOOP %s" % hex_string) try: ack = struct.unpack('c', raw_data[0:1])[0] L = struct.unpack('c', raw_data[1:2])[0] O1 = struct.unpack('c', raw_data[2:3])[0] O2 = struct.unpack('c', raw_data[3:4])[0] pkt_type = struct.unpack('B', raw_data[5:6])[0] next_record = struct.unpack('H', raw_data[6:8])[0] except Exception: self.lastKnownError = "Invalid data format" return False if L != 'L' and O1 != 'O' and O2 != 'O': self.lastKnownError = "Unknown packet encoding" return False pressure = struct.unpack('H', raw_data[8:10])[0] / 1000 pressure *= 3.386 # inHg to kPa log.info("Barometer: %s" % pressure) self.addValue(RMParser.dataType.PRESSURE, timestamp, pressure) outside_temp = struct.unpack('h', raw_data[13:15])[0] / 10 outside_temp = convertFahrenheitToCelsius(outside_temp) log.info("Outside Temp: %s" % outside_temp) self.addValue(RMParser.dataType.TEMPERATURE, timestamp, outside_temp) #wind_speed = struct.unpack('B', raw_data[15:16])[0] #wind_dir = struct.unpack('H', raw_data[17:19])[0] ten_min_avg_wind_spd = struct.unpack('B', raw_data[16:17])[0] ten_min_avg_wind_spd /= 2.237 # mph to mps log.info("Wind Speed (10min avg): %s" % ten_min_avg_wind_spd) out_hum = struct.unpack('B', raw_data[34:35])[0] log.info("Humidity: %s" % out_hum) self.addValue(RMParser.dataType.RH, timestamp, out_hum) #rain_rate = struct.unpack('H', raw_data[42:44])[0] * 0.01 if self.params["useSolarRadiation"]: solar_radiation = struct.unpack('H', raw_data[45:47])[0] log.info("Solar Radiation: %s" % solar_radiation) self.addValue(RMParser.dataType.SOLARRADIATION, timestamp, solar_radiation) day_rain = struct.unpack('H', raw_data[51:53])[0] * 0.01 day_rain = convertInchesToMM(day_rain) log.info("Day Rain: %s", day_rain) self.addValue(RMParser.dataType.RAIN, timestamp, day_rain) if self.params["useStationEvapoTranpiration"]: day_et = struct.unpack('H', raw_data[57:59])[0] / 1000 day_et = convertInchesToMM(day_et) log.info("Day EvapoTranspiration: %s" % day_et) #xmtr_battery_status = struct.unpack('?', raw_data[87:88])[0] #console_battery_volts = ((struct.unpack('h', raw_data[88:90])[0] * 300) / 512) / 100.0 forecast_icon = struct.unpack('c', raw_data[90:91])[0] rainmachine_icon = self.conditionConvert(ord(forecast_icon)) log.info("Condition: %s -> %s" % (ord(forecast_icon), rainmachine_icon)) self.addValue(RMParser.dataType.CONDITION, timestamp, rainmachine_icon) #crc = struct.unpack('h', raw_data[98:100])[0] return True
def perform(self): s = self.settings URL = "http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdXMLclient.php" URLDaily = "http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php" URLParams = [("lat", s.location.latitude), ("lon", s.location.longitude)] + \ [ ("startDate", datetime.date.today().strftime("%Y-%m-%d")), #("endDate", (datetime.date.today() + datetime.timedelta(6)).strftime("%Y-%m-%d")), ("format", "24 hourly"), ("numDays", 6), ("Unit", "e") ] #----------------------------------------------------------------------------------------------- # # Get hourly data. # d = self.openURL(URL, URLParams) if d is None: return tree = e.parse(d) if tree.getroot().tag == 'error': log.error("*** No hourly information found in response!") self.lastKnownError = "Error: No hourly information found" tree.getroot().clear() del tree tree = None else: # We get them in English units need in Metric units maxt = self.__parseWeatherTag(tree, 'temperature', 'maximum') maxt = convertFahrenheitToCelsius(maxt) mint = self.__parseWeatherTag(tree, 'temperature', 'minimum', useStartTimes=False) # for mint we want the end-time to be saved in DB mint = convertFahrenheitToCelsius(mint) temp = self.__parseWeatherTag(tree, 'temperature', 'hourly') temp = convertFahrenheitToCelsius(temp) qpf = self.__parseWeatherTag(tree, 'precipitation', 'liquid') qpf = convertInchesToMM(qpf) dew = self.__parseWeatherTag(tree, 'temperature', 'dew point') dew = convertFahrenheitToCelsius(dew) wind = self.__parseWeatherTag(tree, 'wind-speed', 'sustained') wind = convertKnotsToMS(wind) # These are as percentages pop = self.__parseWeatherTag(tree, 'probability-of-precipitation', '12 hour') humidity = self.__parseWeatherTag(tree, 'humidity', 'relative') minHumidity = self.__parseWeatherTag(tree, 'humidity', 'minimum relative') maxHumidity = self.__parseWeatherTag(tree, 'humidity', 'maximum relative') tree.getroot().clear() del tree tree = None self.addValues(RMParser.dataType.MINTEMP, mint) self.addValues(RMParser.dataType.MAXTEMP, maxt) self.addValues(RMParser.dataType.TEMPERATURE, temp) self.addValues(RMParser.dataType.QPF, qpf) self.addValues(RMParser.dataType.DEWPOINT, dew) self.addValues(RMParser.dataType.WIND, wind) self.addValues(RMParser.dataType.POP, pop) self.addValues(RMParser.dataType.RH, humidity) self.addValues(RMParser.dataType.MINRH, minHumidity) self.addValues(RMParser.dataType.MAXRH, maxHumidity) #----------------------------------------------------------------------------------------------- # # Get daily data. # d = self.openURL(URLDaily, URLParams) tree = e.parse(d) if tree.getroot().tag == 'error': log.error("*** No daily information found in response!") self.lastKnownError = "Error: No daily information found" tree.getroot().clear() del tree tree = None else: conditions = self.__parseWeatherTag(tree, 'conditions-icon', 'forecast-NWS', 'icon-link') parsedConditions = [] for c in conditions: if c and len(c) >= 2: try: cv = self.conditionConvert(c[1].rsplit('.')[-2].rsplit('/')[-1]) except: cv = RMWeatherConditions.Unknown parsedConditions.append((c[0], cv)) tree.getroot().clear() del tree tree = None self.addValues(RMParser.dataType.CONDITION, parsedConditions) if self.parserDebug: log.debug(self.result)
def getHourlyData(self, URL, URLParams, headers): d = self.openURL(URL, URLParams, headers=headers) if d is None: return False try: tree = e.parse(d) except: return False if tree.getroot().tag == 'error': log.error("*** No hourly information found in response!") self.lastKnownError = "Retrying hourly data retrieval" tree.getroot().clear() del tree tree = None return False # Reset lastKnownError from a previous function call self.lastKnownError = "" # We get them in English units need in Metric units maxt = self.__parseWeatherTag(tree, 'temperature', 'maximum') maxt = convertFahrenheitToCelsius(maxt) mint = self.__parseWeatherTag(tree, 'temperature', 'minimum', useStartTimes=False) # for mint we want the end-time to be saved in DB mint = convertFahrenheitToCelsius(mint) temp = self.__parseWeatherTag(tree, 'temperature', 'hourly') temp = convertFahrenheitToCelsius(temp) qpf = self.__parseWeatherTag(tree, 'precipitation', 'liquid') qpf = convertInchesToMM(qpf) dew = self.__parseWeatherTag(tree, 'temperature', 'dew point') dew = convertFahrenheitToCelsius(dew) wind = self.__parseWeatherTag(tree, 'wind-speed', 'sustained') wind = convertKnotsToMS(wind) # These are as percentages pop = self.__parseWeatherTag(tree, 'probability-of-precipitation', '12 hour') pop = convertToInt(pop) humidity = self.__parseWeatherTag(tree, 'humidity', 'relative') humidity = convertToFloat(humidity) minHumidity = self.__parseWeatherTag(tree, 'humidity', 'minimum relative') minHumidity = convertToFloat(minHumidity) maxHumidity = self.__parseWeatherTag(tree, 'humidity', 'maximum relative') maxHumidity = convertToFloat(maxHumidity) tree.getroot().clear() del tree tree = None # Save self.addValues(RMParser.dataType.MINTEMP, mint) self.addValues(RMParser.dataType.MAXTEMP, maxt) self.addValues(RMParser.dataType.TEMPERATURE, temp) self.addValues(RMParser.dataType.QPF, qpf) self.addValues(RMParser.dataType.DEWPOINT, dew) self.addValues(RMParser.dataType.WIND, wind) self.addValues(RMParser.dataType.POP, pop) self.addValues(RMParser.dataType.RH, humidity) self.addValues(RMParser.dataType.MINRH, minHumidity) self.addValues(RMParser.dataType.MAXRH, maxHumidity) return True
def getHourlyData(self, URL, URLParams, headers): d = self.openURL(URL, URLParams, headers=headers) if d is None: return False try: tree = e.parse(d) except: return False #tree = e.parse("/tmp/noaa-fl-2019-06-04-1.xml") if tree.getroot().tag == 'error': log.error("*** No hourly information found in response!") self.lastKnownError = "Retrying hourly data retrieval" tree.getroot().clear() del tree tree = None return False # Reset lastKnownError from a previous function call self.lastKnownError = "" # We get them in English units need in Metric units # 2019-06-01: If we send that weather properties we want (qpf=qpf&mint=mint) in request URL NOAA response forgets # past hours in current day resulting in a forecast requested at the end of the day # having null/0 qpf forgetting the older values which could had more qpf so we need to process QPF first and # determine which entries don't have full days with qpf reported (especially current day) then completely skip # this day for the rest of the weather properties so we don't have a forecast entry with null/0 qpf # Algorithm allows multiple partial days to be skipped because incomplete but we currently only skip today # QPF needs to be the first tag parsed to build the skippedDays structure qpf = self.__parseWeatherTag(tree, 'precipitation', 'liquid', skippedDays=self.skippedDays, addToSkippedDays=True) qpf = convertInchesToMM(qpf) maxt = self.__parseWeatherTag(tree, 'temperature', 'maximum', skippedDays=self.skippedDays) maxt = convertFahrenheitToCelsius(maxt) mint = self.__parseWeatherTag( tree, 'temperature', 'minimum', useStartTimes=False, skippedDays=self.skippedDays ) # for mint we want the end-time to be saved in DB mint = convertFahrenheitToCelsius(mint) temp = self.__parseWeatherTag(tree, 'temperature', 'hourly', skippedDays=self.skippedDays) temp = convertFahrenheitToCelsius(temp) dew = self.__parseWeatherTag(tree, 'temperature', 'dew point', skippedDays=self.skippedDays) dew = convertFahrenheitToCelsius(dew) wind = self.__parseWeatherTag(tree, 'wind-speed', 'sustained', skippedDays=self.skippedDays) wind = convertKnotsToMS(wind) # These are as percentages pop = self.__parseWeatherTag(tree, 'probability-of-precipitation', '12 hour', skippedDays=self.skippedDays) pop = convertToInt(pop) humidity = self.__parseWeatherTag(tree, 'humidity', 'relative', skippedDays=self.skippedDays) humidity = convertToFloat(humidity) minHumidity = self.__parseWeatherTag(tree, 'humidity', 'minimum relative', skippedDays=self.skippedDays) minHumidity = convertToFloat(minHumidity) maxHumidity = self.__parseWeatherTag(tree, 'humidity', 'maximum relative', skippedDays=self.skippedDays) maxHumidity = convertToFloat(maxHumidity) if self.parserDebug: tree.write('noaa-' + str(rmTimestampToDateAsString(rmCurrentTimestamp())) + ".xml") tree.getroot().clear() del tree tree = None # Save self.addValues(RMParser.dataType.MINTEMP, mint) self.addValues(RMParser.dataType.MAXTEMP, maxt) self.addValues(RMParser.dataType.TEMPERATURE, temp) self.addValues(RMParser.dataType.QPF, qpf) self.addValues(RMParser.dataType.DEWPOINT, dew) self.addValues(RMParser.dataType.WIND, wind) self.addValues(RMParser.dataType.POP, pop) self.addValues(RMParser.dataType.RH, humidity) self.addValues(RMParser.dataType.MINRH, minHumidity) self.addValues(RMParser.dataType.MAXRH, maxHumidity) return True
class AmbientWeatherParser(RMParser): parserName = "Ambient Weather Network Parser" parserDescription = "Live personal weather station data from www.ambientweather.net" parserForecast = False parserHistorical = True parserEnabled = False parserDebug = False parserInterval = 60 * 60 # hourly paserHasData = False params = {"apiKey": None, "applicationKey": None, "macAddress": None} req_headers = { "User-Agent": "ambientweather-parser/1.0 (https://github.com/WillCodeForCats/rainmachine-amweather)" } def perform(self): url = 'http://api.ambientweather.net/v1/devices/' + str( self.params["macAddress"]) parameterList = [("apiKey", str(self.params["apiKey"])), ("applicationKey", str(self.params["applicationKey"])), ("limit", "1")] log.info('Getting data from {0}'.format(str(url))) query_string = urllib.urlencode(parameterList) url_query = "?".join([url, query_string]) try: req = urllib2.Request(url=url_query, headers=self.req_headers) data = urllib2.urlopen(url=req, timeout=60) log.debug("Connected to %s" % (url_query)) except Exception, e: self.lastKnownError = "Connection Error" log.error("Error while connecting to %s, error: %s" % (url, e.reason)) return http_status = data.getcode() log.debug("http_status = %s" % (http_status)) if http_status != 200: self.lastKnownError = "HTTP Error " + http_status log.error("URL %s failed with code %s" % (url, http_status)) return station = json.loads(data.read()) for entry in station: dateutc = entry["dateutc"] / 1000 # from milliseconds if 'tempf' in entry: temp = convertFahrenheitToCelsius(entry["tempf"]) self.addValue(RMParser.dataType.TEMPERATURE, dateutc, temp, False) log.debug("TEMPERATURE = %s" % (temp)) self.paserHasData = True if 'humidity' in entry: self.addValue(RMParser.dataType.RH, dateutc, entry["humidity"], False) log.debug("RH = %s" % (entry["humidity"])) self.paserHasData = True if 'windspeedmph' in entry: windspeed = entry["windspeedmph"] * 0.44704 # to meters/sec self.addValue(RMParser.dataType.WIND, dateutc, windspeed, False) log.debug("WIND = %s" % (windspeed)) self.paserHasData = True if 'solarradiation' in entry: solarrad = self.convertRadiationFromWattsToMegaJoules( entry["solarradiation"]) self.addValue(RMParser.dataType.SOLARRADIATION, dateutc, solarrad, False) log.debug("SOLARRADIATION = %s" % (solarrad)) self.paserHasData = True if 'dailyrainin' in entry: rain = convertInchesToMM(entry["dailyrainin"]) self.addValue(RMParser.dataType.RAIN, dateutc, rain, False) log.debug("RAIN = %s" % (rain)) self.paserHasData = True if 'baromrelin' in entry: pressure = entry["baromrelin"] * 3.38639 # to kPa self.addValue(RMParser.dataType.PRESSURE, dateutc, pressure, False) log.debug("PRESSURE = %s" % (pressure)) self.paserHasData = True if 'dewPoint' in entry: dewpoint = convertFahrenheitToCelsius(entry["dewPoint"]) self.addValue(RMParser.dataType.DEWPOINT, dateutc, dewpoint, False) log.debug("DEWPOINT = %s" % (dewpoint)) self.paserHasData = True if self.paserHasData: log.info("Successful update from station %s" % (str(self.params["macAddress"]))) return True else: self.lastKnownError = "No Data From Station" log.error("Connected, but no data returned from station %s" % (str(self.params["macAddress"]))) return