def __parseXMLData(self, tree): dateFormat = "%Y-%m-%dT%H:%M:%SZ" data = {} for w in tree.getroot().find('product'): for wd in w.find('location'): tag = wd.tag from_time = w.get('from') to_time = w.get('to') intervalStartTimestamp = rmTimestampFromDateAsString( from_time, dateFormat) + 1 # 1 second more than hour boundary intervalEndTimestamp = rmTimestampFromDateAsString( to_time, dateFormat) - 1 # 1 second less than hour boundary day, startTimeStr = from_time.split("T") endTimeStr = to_time.split("T")[1] if tag not in data: data[tag] = {} if day not in data[tag]: data[tag][day] = [] startHourStr = startTimeStr.split(":")[0] endHourStr = endTimeStr.split(":")[0] try: if (tag == 'windDirection'): val = toFloat(wd.get('deg')) elif (tag == 'windSpeed'): val = toFloat(wd.get('mps')) elif (tag == 'symbol'): condition = toInt(wd.get('number')) val = self.conditionConvert(condition) elif (tag == 'cloudiness' or tag == 'fog' or tag == 'lowClouds' or tag == 'mediumClouds' or tag == 'highClouds'): val = toFloat(wd.get('percent')) else: val = toFloat(wd.get('value')) # hPa -> kPa if (tag == 'pressure'): val = val / 10 except Exception, e: val = None log.debug(e) data[tag][day].append({ "startHour": startHourStr, "endHour": endHourStr, "start": intervalStartTimestamp, "end": intervalEndTimestamp, "value": val })
def perform(self): days = self.params["historicDays"] intervals = days / self.maxAllowedDays + (days % self.maxAllowedDays != 0) lastIntervalStartDay = datetime.date.today() if intervals > 1: days = self.maxAllowedDays log.debug("Days: %d Intervals: %d" % (days, intervals)) for i in range(0, intervals): startDay = lastIntervalStartDay - datetime.timedelta( days=1) # CIMIS real data starts from yesterday endDay = startDay - datetime.timedelta(days=(days + 1)) lastIntervalStartDay = endDay try: self.__retrieveData( endDay, startDay ) # we call with startDay/endDay swapped because CIMIS expects historic intervals except Exception, e: log.error("*** Error running CIMIS parser") self.lastKnownError = "Error: Data retrieval failed" log.exception(e)
def getNearbyStationsNoKey(self): MIN_STATIONS = 1 MAX_STATIONS = 20 s = self.settings llat = s.location.latitude llon = s.location.longitude stationsURL = "https://stationdata.wunderground.com/cgi-bin/stationdata?v=2.0&type=ICAO%2CPWS&units=metric&format=json&maxage=1800&maxstations=" \ + str(MAX_STATIONS) + "&minstations=" + str(MIN_STATIONS) + "¢erLat=" + str(llat) + "¢erLon=" \ + str(llon) + "&height=400&width=400&iconsize=2&callback=__ng_jsonp__.__req1.finished" try: # WARNING: WE PROBABLY SHOULD FAIL IF WE CAN'T GET STATIONS IF USER KNOWS STATION_ID log.debug("Downloading station data from: %s" % stationsURL) d = self.openURL(stationsURL, headers=self.headers) if d is None: self.lastKnownError = "Cannot download nearby stations" log.error(self.lastKnownError) # extract object from callback parameter stationsData = d.read() stationsObj = stationsData[stationsData. find("{"):stationsData.rfind("}") + 1] # log.info(stationsObj) stations = json.loads(stationsObj) self.parseNearbyStationsNoKey(stations) except Exception, e: self.lastKnownError = "ERROR: Cannot get nearby stations" log.error(self.lastKnownError) return
def __manglePassword(self, password): if not password or len(password) != 96: return None tokenSize = len(password) / 16 tokens = [] tokens.append("3" + password[(0 * tokenSize):(1 * tokenSize)]) tokens.append("b" + password[(15 * tokenSize):(16 * tokenSize)]) mangle = "" count = 15 while count >= 0: index = random.randint(0, count) mangle += tokens[index] del tokens[index] count -= 1 log.debug("Password: %s" % password) log.debug("Mangle: %s" % mangle) return mangle
def __fahrenheitToCelsius(self, temp): try: temp = float(temp) return (temp - 32) * 5.0/9.0 except: log.debug("Can't convert fahrenheit to celsius !") return None
def __knotsToMS(self, knots): try: knots = float(knots) return knots * 0.514444 except: log.debug("Can't convert knots to m/s !") return None
def __inchesToMM(self, inches): try: inches = float(inches) return inches * 25.4 except: log.debug("Can't convert inches to mm !") return None
def __diagNetwork(self): try: with open("/proc/net/route") as f: for line in f: fields = line.strip().split() if fields[ 1] != "00000000": # default gateway destination 0.0.0.0 continue #log.debug(fields) if int( fields[3], 16 ) & 2: # check route to be UG from the third field which is in base16 self.__networkStatus = True try: self.__networkGateway = socket.inet_ntoa( struct.pack("=L", int(fields[2], 16))) #self.__networkGateway = ".".join([str(int(fields[2][i:i+2], 16)) for i in range(0, len(fields[2]), 2)]) # depends on endianess except: self.__networkGateway = None log.debug("Cannot get gateway address.") log.debug("Network gateway (%s) up on interface %s" % (self.__networkGateway, fields[0])) return except: log.error("Cannot find /proc entry for network diag") self.__networkStatus = False
def perform(self): timeNow = rmNowDateTime() timeNow = rmNowDateTime().fromordinal(timeNow.toordinal()-1) yyyy = timeNow.year mm = timeNow.month dd = timeNow.day log.debug("Wunderground parser - perform") self.params["_nearbyStationsIDList"] = [] self.params["_airportStationsIDList"] = [] apiKey = self.params.get("apiKey", None) if(apiKey is None or not apiKey or not isinstance(apiKey, str)): #TODO: implement xml WUnderground parser log.error("No API Key provided") self.lastKnownError = "Error: No API Key provided" return self.apiURL = "http://api.wunderground.com/api/" + str(apiKey) + "/geolookup/conditions/hourly10day/history_" + str(yyyy) + str(mm).zfill(2) + str(dd).zfill(2) +"/q/" if (self.params.get("useCustomStation")): stationName = self.params.get("customStationName") if(stationName is None or not stationName or not isinstance(stationName, str)): log.error("Station ID cannot be empty") self.lastKnownError = "Error: Station ID cannot be empty" return log.debug("getting data from specified station") if len(stationName) > 4: self.apiURL += "pws:" + stationName + ".json" #url for pws else: self.apiURL += stationName + ".json" #url for pws else: s = self.settings llat = s.location.latitude llon = s.location.longitude self.apiURL += str(llat) + "," + str(llon) + ".json" # self.params["useCustomStation"] = False log.debug(self.apiURL) d = self.openURL(self.apiURL) jsonContent = d.read() if jsonContent is None: log.error("Failed to get WUnderground JSON contents") self.lastKnownError = "Error: Bad response" return self.jsonResponse = json.loads(jsonContent) #populate nearby stations log.debug("Wunderground parser - get nearby stations") self.getNearbyStations(self.jsonResponse) log.debug("Wunderground parser - get data") self.getStationData(self.jsonResponse) return
def rmGetSunriseTimestampForDayTimestamp(ts, lat, lon, elevation): if lat is None or lon is None: log.debug("Latitude or longitude is not set. Returning same timestamp") return ts Jtr, w0 = computeSuntransitAndDayLenghtForDayTs(ts, lat, -lon, elevation) Jrise = Jtr-w0/360 tsJrise = julianDayToUTC(Jrise) return tsJrise
def executeCommand(self, command): log.debug("Schedule execute command: %s" % `command.name`) log.debug(command) self.messageQueue.put(command) if command.event: command.wait() log.debug(command) log.debug("Command finished %s" % `command.name`) return command.result
def __getForecastData(self, forecast): dayTimestamp = rmCurrentDayTimestamp() if "list" not in forecast: self.lastKnownError = "Error: Missing data cannot parse response JSON." log.info(self.lastKnownError) return for entry in forecast["list"]: timestamp = entry["dt"] if self.parserDebug: log.info("Date: %s" % rmTimestampToDateAsString(timestamp)) maxtemp = None mintemp = None temp = None humidity = None pressure = None if "main" in entry: maxtemp = entry["main"].get("temp_max") mintemp = entry["main"].get("temp_min") temp = entry["main"].get("temp") humidity = entry["main"].get("humidity") pressure = entry["main"].get("grnd_level") try: pressure = pressure / 10 # hPa to kPa except: pressure = None self.addValue(RMParser.dataType.MINTEMP, timestamp, mintemp) self.addValue(RMParser.dataType.MAXTEMP, timestamp, maxtemp) self.addValue(RMParser.dataType.TEMPERATURE, timestamp, temp) self.addValue(RMParser.dataType.RH, timestamp, humidity) self.addValue(RMParser.dataType.PRESSURE, timestamp, pressure) qpf = None if "rain" in entry: qpf = entry["rain"].get("3h") self.addValue(RMParser.dataType.QPF, timestamp, qpf) wind = None if "wind" in entry: wind = entry["wind"].get("speed") self.addValue(RMParser.dataType.WIND, timestamp, wind) icon = None if entry["weather"][0]: icon = self.conditionConvert(entry["weather"][0].get("id")) self.addValue(RMParser.dataType.CONDITION, timestamp, icon) if self.parserDebug: log.debug(self.result)
def isInMonthRestriction(self, timestamp): d = datetime.fromtimestamp(timestamp) currentMonth = d.month - 1 if self.globalRestrictions.noWaterInMonths[currentMonth] == 1: log.debug("Restricted for %d month" % (currentMonth)) return True return False
def isInDayRestriction(self, timestamp): d = datetime.fromtimestamp(timestamp) currentWeekDay = d.weekday() if self.globalRestrictions.noWaterInWeekDays[currentWeekDay] == 1: log.debug("Restricted for %d weekday" % currentWeekDay) return True return False
def getStationData(self, jsonData): #daily summary for yesterday try: dailysummary = jsonData["history"]["dailysummary"][0] temperature = self.__toFloat(dailysummary["meantempm"]) mintemp = self.__toFloat(dailysummary["mintempm"]) maxtemp = self.__toFloat(dailysummary["maxtempm"]) rh = self.__toFloat(dailysummary["humidity"]) minrh = self.__toFloat(dailysummary["minhumidity"]) maxrh = self.__toFloat(dailysummary["maxhumidity"]) dewpoint = self.__toFloat(dailysummary["meandewptm"]) wind = self.__toFloat(dailysummary["meanwindspdm"]) if wind is not None: wind = wind / 3.6 # convertred from kmetersph to mps maxpressure = self.__toFloat(dailysummary["maxpressurem"]) minpressure = self.__toFloat(dailysummary["minpressurem"]) pressure = None if maxpressure is not None and minpressure is not None: pressure = (maxpressure / 2 + minpressure / 2) / 10 #converted to from mb to kpa rain = self.__toFloat(dailysummary["precipm"]) #time utc jutc = jsonData["history"]["utcdate"] yyyy = self.__toInt(jutc["year"]) mm = self.__toInt(jutc["mon"]) dd = self.__toInt(jutc["mday"]) hour = self.__toInt(jutc["hour"]) mins = self.__toInt(jutc["min"]) log.debug("Observations for date: %d/%d/%d Temp: %s, Rain: %s" % (yyyy, mm, dd, temperature, rain)) dd = datetime.datetime(yyyy, mm, dd, hour, mins) timestamp = calendar.timegm(dd.timetuple()) timestamp = self.__parseDateTime(timestamp) self.addValue(RMParser.dataType.TEMPERATURE, timestamp, temperature) self.addValue(RMParser.dataType.MINTEMP, timestamp, mintemp) self.addValue(RMParser.dataType.MAXTEMP, timestamp, maxtemp) self.addValue(RMParser.dataType.RH, timestamp, rh) self.addValue(RMParser.dataType.MINRH, timestamp, minrh) self.addValue(RMParser.dataType.MAXRH, timestamp, maxrh) self.addValue(RMParser.dataType.WIND, timestamp, wind) self.addValue(RMParser.dataType.RAIN, timestamp, rain) # self.addValue(RMParser.dataType.QPF, timestamp, rain) # uncomment to report measured rain as previous day QPF self.addValue(RMParser.dataType.DEWPOINT, timestamp, dewpoint) self.addValue(RMParser.dataType.PRESSURE, timestamp, pressure) except: log.warning("Failed to get daily summary") self.lastKnownError = "Warning: Failed to get daily summary" self.__getSimpleForecast()
def __refreshWIFI(self): timestamp = rmCurrentTimestamp() lastWIFICheckTimestamp = globalWIFI.wifiInterface.lastWIFICheckTimestamp oldIP = globalWIFI.wifiInterface.ipAddress if lastWIFICheckTimestamp is None or oldIP is None or ( timestamp - lastWIFICheckTimestamp) >= self.__wifiRefreshTimeout: try: globalWIFI.detect() if oldIP != globalWIFI.wifiInterface.ipAddress: log.info( "Refreshed WIFI Information. (old: %s new ip: %s)" % ( ` oldIP `, ` globalWIFI.wifiInterface.ipAddress `)) if RMOSPlatform().AUTODETECTED == RMOSPlatform.ANDROID: return # Handle None IP if globalWIFI.wifiInterface.ipAddress is None: if self.__lastNoneIpTimestamp is None or ( timestamp - self.__lastNoneIpTimestamp ) < self.__wifiNoneIpTimeout: # First occurrence of None IP OR we can wait some more time. if self.__lastNoneIpTimestamp is None: self.__lastNoneIpTimestamp = timestamp log.debug( "Refreshed WIFI Information - no IP detected. Give it some more time: %d seconds!" % (self.__wifiNoneIpTimeout - (timestamp - self.__lastNoneIpTimestamp), )) return else: globalWIFI.restart() log.warn( "Refreshed WIFI Information - WIFI quick reloaded because no IP detected. New IP is %s" % ` globalWIFI.wifiInterface.ipAddress `) self.__lastNoneIpTimestamp = None # Reset None IP timestamp. # Check if we never connected to this AP, set back AP mode and restart app if globalWIFI.wifiInterface.mode == "managed" and not globalWIFI.hasConnectedOnce( ): if globalWIFI.wifiInterface.hasClientLink: globalWIFI.saveHasConnectedOnce(True) else: log.warning( "WIFI Watcher Client IP (%s) configuration failed, restarting in AP mode." % oldIP) globalWIFI.setDefaultAP() globalWIFI.saveHasConnectedOnce(False) globalWIFI.restart() self.__mainManager.touchWakeMessage() except Exception, e: log.error(e)
def perform(self): # downloading data from a URL convenience function since other python libraries can be used URL = "http://lab.zanek.net/mesonet/api/currentobservations" stationID = "ALTU" data = self.openURL(URL) if data is None: return stationsData = json.loads(data.read()) if stationsData is None: self.lastKnownError = "Error: Invalid response from server" return timestamp = rmCurrentTimestamp() for station in stationsData: if station['STID'] == stationID: try: rain = self.__toFloat(station.get("RAIN")) except: rain = None try: tmin = self.__toFloat(station.get("TMIN")) tmax = self.__toFloat(station.get("TMAX")) except: self.lastKnownError = "Error: No minimum or maximum temperature can be retrieved" return try: pressure = self.__toFloat(station.get("PRES")) except: pressure = None try: wind = self.__toFloat(station.get("WSPD")) except: wind = None try: dew = self.__toFloat(station.get("TDEW")) except: dew = None self.addValue(RMParser.dataType.MINTEMP, timestamp, tmin) self.addValue(RMParser.dataType.MAXTEMP, timestamp, tmax) self.addValue(RMParser.dataType.RAIN, timestamp, rain) self.addValue(RMParser.dataType.PRESSURE, timestamp, pressure) self.addValue(RMParser.dataType.WIND, timestamp, wind) self.addValue(RMParser.dataType.DEWPOINT, timestamp, dew) if self.parserDebug: log.debug(self.result)
def __toUtc(self, jutc, t, r, w): # time utc yyyy = self.__toInt(jutc[:4]) mm = self.__toInt(jutc[4:6]) dd = self.__toInt(jutc[6:8]) hour = self.__toInt(jutc[8:10]) mins = self.__toInt(jutc[10:12]) log.debug( "Observations for date: {:d}/{:d}/{:d}, time: {:d}{:d}z Temp: {}, Rain: {}, Wind: {}" .format(yyyy, mm, dd, hour, mins, t, r, w))
def __parseWeatherTag(self, tree, tag, typeConvert = None): values = [] startTimes = [] lastEndTime = None for w in tree.getroot().find('product'): for wd in w.find('location'): if wd.tag == tag: from_time = w.get('from') to_time = w.get('to') ft = datetime.datetime.strptime(from_time, "%Y-%m-%dT%H:%M:%SZ") tt = datetime.datetime.strptime(to_time, "%Y-%m-%dT%H:%M:%SZ") td = tt - ft shouldSkip = False # skip 6h intervals as they aren't disjoint between them (eg: 0-6, 3-9) # only if we had a previous report with same end time if lastEndTime is not None and lastEndTime == tt and td.seconds == 6 * 3600: shouldSkip = True log.debug("Tag %s [%s - %s] Skip: %s" % (tag, from_time, to_time, shouldSkip)) if shouldSkip: continue lastEndTime = tt startTimes.append(self.__parseDateTime(ft)) try: if (tag == 'windDirection'): val = wd.get('deg') elif (tag == 'windSpeed'): val = wd.get('mps') elif (tag == 'symbol'): condition = int(wd.get('number'), RMParser.conditionType.Unknown) val = self.conditionConvert(condition) elif (tag == 'cloudiness' or tag == 'fog' or tag == 'lowClouds' or tag == 'mediumClouds' or tag == 'highClouds'): val = wd.get('percent') else: val = wd.get('value') if typeConvert == 'int': val = int(val) if typeConvert == 'float': val = float(val) # hPa -> kPa if (tag == 'pressure'): val = val / 10 except Exception, e: val = None log.debug(e) values.append(val)
def __writeNotification(string): #log.info("NotifyCloud: %s" % string) try: if stat.S_ISFIFO(os.stat(RMNotification.__cloudClientControlFile).st_mode) > 0: fd = os.open(RMNotification.__cloudClientControlFile, os.O_WRONLY | os.O_NONBLOCK) try: os.write(fd, string) log.debug("Notified cloud client about change") except Exception, e: log.debug("Can't notify cloud client about settings change %s", str(e)) finally: os.close(fd)
def performWithDataFeeds(self, station): s = self.settings URLHourly = "http://fawn.ifas.ufl.edu/controller.php/lastHour/summary/json" URLDaily = "http://fawn.ifas.ufl.edu/controller.php/lastDay/summary/json" URLParams = [] useHourly = self.params.get("useHourly", False) #----------------------------------------------------------------------------------------------- # # Get hourly data. # if useHourly: try: log.info("Retrieving data from: %s" % URLHourly) d = self.openURL(URLHourly, URLParams) if d is None: return json_data = d.read() json_data = json_data.replace("'","\"") hourly = json.loads(json_data) for entry in hourly: # only selected station if int(entry.get("StationID")) == station: dateString = entry.get("startTime") #timestamp = rmTimestampFromDateAsStringWithOffset(dateString) timestamp = rmTimestampFromDateAsString(dateString[:-6], '%Y-%m-%dT%H:%M:%S') if timestamp is None: log.debug("Cannot convert hourly data startTime: %s to unix timestamp" % dateString) continue # Add 12h in the future for FAWN timestamp to fix badly reported offset and make it middle of the day UTC (Dragos) timestamp += 12 * 60 *60 self.addValue(RMParser.dataType.TEMPERATURE, timestamp, self.__toFloat(entry.get("t2m_avg"))) self.addValue(RMParser.dataType.MINTEMP, timestamp, self.__toFloat(entry.get("t2m_min"))) self.addValue(RMParser.dataType.MAXTEMP, timestamp, self.__toFloat(entry.get("t2m_max"))) # km/h -> m/s self.addValue(RMParser.dataType.WIND, timestamp, 0.27777777777778 * self.__toFloat(entry.get("ws_avg"))) # cm -> mm self.addValue(RMParser.dataType.RAIN, timestamp, 10 * self.__toFloat(entry.get("rain_sum"))) self.addValue(RMParser.dataType.DEWPOINT, timestamp, self.__toFloat(entry.get("dp_avg"))) self.addValue(RMParser.dataType.RH, timestamp, self.__toFloat(entry.get("rh_avg"))) if self.parserDebug: log.debug(self.result) except Exception, e: self.lastKnownError = "Error retrieving hourly data." log.error(self.lastKnownError) log.exception(e)
def perform(self): s = self.settings URLHourly = "http://fawn.ifas.ufl.edu/controller.php/lastHour/summary/json" URLDaily = "http://fawn.ifas.ufl.edu/controller.php/lastDay/summary/json" URLParams = [] useHourly = self.params.get("useHourly", False) # ----------------------------------------------------------------------------------------------- # # Get hourly data. # if useHourly: try: d = self.openURL(URLHourly, URLParams) if d is None: return json_data = d.read() json_data = json_data.replace("'", '"') hourly = json.loads(json_data) for entry in hourly: # only selected station if int(entry.get("StationID")) == self.params.get("station"): dateString = entry.get("startTime") # timestamp = rmTimestampFromDateAsStringWithOffset(dateString) timestamp = rmTimestampFromDateAsString(dateString[:-6], "%Y-%m-%dT%H:%M:%S") if timestamp is None: log.debug("Cannot convert hourly data startTime: %s to unix timestamp" % dateString) continue # Add 12h in the future for FAWN timestamp to fix badly reported offset and make it middle of the day UTC (Dragos) timestamp += 12 * 60 * 60 self.addValue(RMParser.dataType.TEMPERATURE, timestamp, self.__toFloat(entry.get("t2m_avg"))) self.addValue(RMParser.dataType.MINTEMP, timestamp, self.__toFloat(entry.get("t2m_min"))) self.addValue(RMParser.dataType.MAXTEMP, timestamp, self.__toFloat(entry.get("t2m_max"))) # km/h -> m/s self.addValue( RMParser.dataType.WIND, timestamp, 0.27777777777778 * self.__toFloat(entry.get("ws_avg")) ) # cm -> mm self.addValue(RMParser.dataType.RAIN, timestamp, 10 * self.__toFloat(entry.get("rain_sum"))) self.addValue(RMParser.dataType.DEWPOINT, timestamp, self.__toFloat(entry.get("dp_avg"))) self.addValue(RMParser.dataType.RH, timestamp, self.__toFloat(entry.get("rh_avg"))) if self.parserDebug: log.debug(self.result) except Exception, e: log.error("*** Error retrieving hourly data from FAWN") log.exception(e)
def installParser(self, tempFilePath, fileName): filePath = os.path.abspath( os.path.join(os.path.dirname(os.path.abspath(__file__)), "parsers", fileName)) shutil.move(tempFilePath, filePath) try: module = imp.load_source(fileName, filePath) log.info(" * Parser %s successful loaded from file '%s'" % (fileName, filePath)) parser = RMParser.parsers[-1] # Last added parser enabled = parser.isEnabledForLocation(globalSettings.location.timezone, \ globalSettings.location.latitude, \ globalSettings.location.longitude ) parserConfig, isNew = self.parserTable.addParser( fileName, parser.parserName, enabled, parser.params) if not isNew: params = self.parserTable.getParserParams(parserConfig.dbID) if params: parser.params = params RMParser.parsers.pop() #delete old entry pkeys = self.parsers.keys() for pkey in pkeys: if parserConfig.dbID is pkey.dbID: del self.parsers[pkey] self.parsers[parserConfig] = parser parserConfig.userDataTypes = self.userDataTypeTable.addRecords( parser.userDataTypes) self.parserUserDataTypeTable.addRecords(parserConfig.dbID, parserConfig.userDataTypes) log.debug(parserConfig) return True except Exception as e: try: if os.path.exists(filePath): os.remove(filePath) except Exception, e: log.exception(e) log.error(" * Error installing/loading parser %s from file '%s'" % (fileName, filePath)) log.exception(e)
def getUptime(self): uptimeSeconds = 0 if RMOSPlatform().AUTODETECTED == RMOSPlatform.ANDROID: uptimeSeconds = getAlarmElapsedRealTime() else: try: with open('/proc/uptime') as f: procLine = f.readline().split()[0] uptimeSeconds = int(float(procLine)) except (IOError, OSError): log.debug("Cannot get platform uptime.") return uptimeSeconds
def isInFreezeProtect(self, timestamp): if self.globalRestrictions.useFreezeControlTemp: dayMinTemp = self.__dayMinTemperature.get(rmGetStartOfDay(timestamp), None) if dayMinTemp is None: log.debug("No minimum temperature for %d found, won't restrict." % rmGetStartOfDay(timestamp)) return False if int(dayMinTemp) <= int(self.globalRestrictions.minFreezeControlTemp): log.debug("Restricted for minimum temperature %s <= %s" % \ (`dayMinTemp`, `self.globalRestrictions.minFreezeControlTemp`)) return True return False
def perform(self): # downloading data from a URL convenience function since other python libraries can be used URL = self.params["URL"] data = self.openURL(URL) if data is None: self.lastKnownError = "Error: No data received from server" return #xmldata = e.parse("/tmp/IDQ11295.xml") xmldata = e.parse(data) for node in xmldata.getroot().getiterator(tag="area"): if node.attrib['description'] != self.params["city"]: continue for subnode in node.getiterator(tag="forecast-period"): subnodeDate = subnode.get("start-time-utc") subnodeTimestamp = rmTimestampFromDateAsString( subnodeDate, '%Y-%m-%dT%H:%M:%SZ') log.info("%s" % subnodeDate) for element in subnode.getiterator(tag="element"): mint = None maxt = None qpfMin = None qpfMax = None qpfAvg = None type = element.get("type") if type == "air_temperature_minimum": try: mint = self.__toFloat(element.text) log.info("\tMin Temp: %s" % mint) self.addValue(RMParser.dataType.MINTEMP, subnodeTimestamp, mint) except: log.debug("Cannot get minimum temperature") elif type == "air_temperature_maximum": try: maxt = self.__toFloat(element.text) self.addValue(RMParser.dataType.MAXTEMP, subnodeTimestamp, maxt) log.info("\tMax Temp: %s" % maxt) except: log.debug("Cannot get max temperature") elif type == "precipitation_range": try: qpfMin, _, qpfMax, _ = element.text.split( ) # will result in ['15', 'to', '35', 'mm'] qpfAvg = (self.__toFloat(qpfMin) + self.__toFloat(qpfMax)) / 2 log.info("\tQPF Avg: %s" % qpfAvg) self.addValue(RMParser.dataType.QPF, subnodeTimestamp, qpfAvg) except: log.debug("Cannot get precipitation forecast") if self.parserDebug: log.debug(self.result)
def doExecuteCommand(self, command): log.debug(command.name) try: if command.args is None and command.kwargs is None: command.result = command.command() elif command.kwargs is None: command.result = command.command(*command.args) elif command.args is None: command.result = command.command(**command.kwargs) else: command.result = command.command(*command.args, **command.kwargs) except Exception, e: log.error(command.name) log.error(e)
def conditionConvert(self, weathercodes, cloudcodes): temparr = str(weathercodes).split(":") log.debug("Weatherarray: {}, conditions: {}".format( temparr, cloudcodes)) intensity = temparr[1] conditionStr = temparr[2] if (conditionStr == 'L') or (conditionStr == 'ZL'): return RMParser.conditionType.LightRain elif (conditionStr == 'R') or (conditionStr == 'RW') or ( conditionStr == 'RS') or (conditionStr == 'ZR') or (conditionStr == 'WM'): if (intensity == 'H') or (intensity == 'VH'): return RMParser.conditionType.HeavyRain else: return RMParser.conditionType.LightRain elif 'M' in conditionStr: return RMParser.conditionType.LightRain elif 'BR' in conditionStr: return RMParser.conditionType.LightRain elif 'S' in conditionStr: return RMParser.conditionType.Snow elif 'IP' in conditionStr: return RMParser.conditionType.IcePellets elif 'A' in conditionStr: return RMParser.conditionType.IcePellets elif (conditionStr == 'F') or (conditionStr == 'ZF'): return RMParser.conditionType.Fog elif 'H' in conditionStr: return RMParser.conditionType.Haze elif 'T' in conditionStr: return RMParser.conditionType.Thunderstorm elif 'K' in conditionStr: return RMParser.conditionType.Smoke elif '' in conditionStr: if 'OV' in cloudcodes: return RMParser.conditionType.Overcast elif 'CL' in cloudcodes: return RMParser.conditionType.Fair elif 'SC' in cloudcodes: return RMParser.conditionType.Fair elif 'BK' in cloudcodes: return RMParser.conditionType.PartlyCloudy elif 'FW' in cloudcodes: return RMParser.conditionType.Fair else: return RMParser.conditionType.Unknown
def renewAccesTokenIfNeeded(self): try: if self.accessTokenExpiration < time.time(): postParams = { "grant_type" : "refresh_token", "refresh_token" : self.refreshToken, "client_id" : self.clientID, "client_secret" : self.clientSecret } response = self.postRequest(self.authReq, postParams) self.accessToken = response['access_token'] self.refreshToken = response['refresh_token'] self.accessTokenExpiration = int(response['expire_in']) + time.time() except: log.debug("Failed to refresh token")
def __refreshWatchDog(self): timestamp = rmCurrentTimestamp() if self.__lastWatchdogTimestamp is None or (timestamp - self.__lastWatchdogTimestamp) >= self.__watchDogTimeout: if self.__watchDogDescriptor is None: try: self.__watchDogDescriptor = open(self.__watchDogFile, 'w') log.info("Opened system watchdog file %s with timeout %d" % (self.__watchDogFile, self.__watchDogTimeout)) except Exception, e: log.error(e) try: self.__watchDogDescriptor.write(`timestamp`) self.__watchDogDescriptor.flush() log.debug("PING Hardware Watchdog") except Exception, e: log.error(e)
def __diagWifi(self): try: with open("/proc/net/wireless") as f: for line in f: fields = line.strip().split() #log.debug(fields) if not fields[0].endswith(":"): continue log.debug("Wireless interface %s up" % fields[0]) self.__hasWifi = True return except: log.error("Cannot find /proc entry for wireless diag") self.__hasWifi = False
def __upload(self, localPath, file): with open(os.path.join(localPath, file), "rb") as f: log.debug("Uploading file: %s" % file) extraRemotePath = os.path.split(file)[0] if extraRemotePath: if os.path.isabs(extraRemotePath): extraRemotePath = extraRemotePath.lstrip("/") file = file.lstrip("/") try: self.__ftp.mkd(extraRemotePath) except Exception, e: log.debug("Folder %s/ creation failed: %s" % (extraRemotePath, e)) self.__ftp.storbinary("STOR " + file, f)
def getFromProc(self): status = None result = {'peak': 0, 'rss': 0} try: status = open(self.statpath) for line in status: parts = line.split() key = parts[0][2:-1].lower() if key in result: result[key] = int(parts[1]) except (IOError, OSError): log.debug("Cannot get memory stats from /proc") finally: if status is not None: status.close() return result
def renewAccesTokenIfNeeded(self): try: if self.accessTokenExpiration < time.time(): postParams = { "grant_type": "refresh_token", "refresh_token": self.refreshToken, "client_id": self.clientID, "client_secret": self.clientSecret } response = self.postRequest(self.authReq, postParams) self.accessToken = response['access_token'] self.refreshToken = response['refresh_token'] self.accessTokenExpiration = int( response['expire_in']) + time.time() except: log.debug("Failed to refresh token")
def clientOauth(self): postParams = { "grant_type": "password", "client_id": self.clientID, "client_secret": self.clientSecret, "username": self.username, "password": self.password, "scope": "read_station" } try: resp = self.postRequest(self.authReq, postParams) self.accessToken = resp['access_token'] self.refreshToken = resp['refresh_token'] self.accessTokenExpiration = int(resp['expire_in']) + time.time() except: log.debug("Failed to get oauth token")
def clientOauth(self): postParams = { "grant_type" : "password", "client_id" : self.clientID, "client_secret" : self.clientSecret, "username" : self.username, "password" : self.password, "scope" : "read_station" } # try: resp = self.postRequest(self.authReq, postParams) self.accessToken = resp['access_token'] self.refreshToken = resp['refresh_token'] self.accessTokenExpiration = int(resp['expire_in']) + time.time() # except: log.debug("Failed to get oauth token")
def postRequest(self, url, params): params = urlencode(params) headers = {"Content-Type" : "application/x-www-form-urlencoded;charset=utf-8"} req = urllib2.Request(url=url, data=params, headers=headers) resp = None try: resp = urllib2.urlopen(req).read() except urllib2.URLError, e: log.debug(e) try: context = ssl._create_unverified_context() resp = urllib2.urlopen(req, context=context).read() except Exception, e: log.exception(e) return None
def __diagWifi(self): try: with open("/proc/net/wireless") as f: for line in f: fields = line.strip().split() #log.debug(fields) if not fields[0].endswith(":"): continue log.debug("Wireless interface %s up" % fields[0]) self.__hasWifi = True return except: log.error("Cannot find /proc entry for wireless diag") self.__hasWifi= False
def __writeNotification(string): #log.info("NotifyCloud: %s" % string) try: if stat.S_ISFIFO( os.stat( RMNotification.__cloudClientControlFile).st_mode) > 0: fd = os.open(RMNotification.__cloudClientControlFile, os.O_WRONLY | os.O_NONBLOCK) try: os.write(fd, string) log.debug("Notified cloud client about change") except Exception, e: log.debug( "Can't notify cloud client about settings change %s", str(e)) finally: os.close(fd)
def apiCall(self, apiURL): # try: d = self.openURL(apiURL) # request = urllib2.urlopen(apiURL) jsonContent = d.read() if jsonContent is None: log.debug("Failed to get Aeris JSON contents") self.lastKnownError = "Error: Bad response" return log.debug("jsonContent: {}".format(jsonContent)) jsonResponse = (json.loads(jsonContent)) # print (jsonResponse) if (jsonResponse['success']): return jsonResponse
def perform(self): if self.params["minTemp"] is not None: self.tempMin = self.params["minTemp"] if self.params["maxTemp"] is not None: self.tempMax = self.params["maxTemp"] startDayTimestamp = (self._currentDayTimestamp()) #prediction timestamps noOfDays = 6 arrTimestamps = [x for x in range(startDayTimestamp, startDayTimestamp+noOfDays*24*3600, 4*3600)] #----------------------------------------------------------------------------------------------- # # Get hourly data. self.addValues(RMParser.dataType.TEMPERATURE, self._generatePeriodicalData(arrTimestamps, self.tempMin , self.tempMax, 6, -2.5)) self.addValues(RMParser.dataType.MINTEMP, self._generateCumulativeData(arrTimestamps, self.tempMin/2, self.tempMin*2)) self.addValues(RMParser.dataType.MAXTEMP, self._generateCumulativeData(arrTimestamps, self.tempMax/2, self.tempMax*2)) self.addValues(RMParser.dataType.DEWPOINT, self._generateCumulativeData(arrTimestamps, self.dewMin, self.dewMax)) self.addValues(RMParser.dataType.WIND, self._generateCumulativeData(arrTimestamps, self.windMin, self.windMax)) self.addValues(RMParser.dataType.POP, self._generateCumulativeData(arrTimestamps, self.popMin, self.popMax)) self.addValues(RMParser.dataType.RH, self._generatePeriodicalData(arrTimestamps, 2*math.fabs(self.tempMin) , 2*math.fabs(self.tempMax), 6, 0)) #----------------------------------------------------------------------------------------------- # # Get daily data. # #self.addValues(RMParser.dataType.CONDITION, parsedConditions) # self._generateQpfRainModelData() # ##add history for yesterday startYesterday = self._currentDayTimestamp() - 24*3600 self.addValue(RMParser.dataType.TEMPERATURE, startYesterday, (self.tempMax+self.tempMin)*random.random()) self.addValue(RMParser.dataType.MINTEMP, startYesterday, self.tempMin*random.random()) self.addValue(RMParser.dataType.MAXTEMP, startYesterday, self.tempMax*random.random()) self.addValue(RMParser.dataType.RH, startYesterday, (self.humidityMin+self.humidityMax)*random.random()) self.addValue(RMParser.dataType.MINRH, startDayTimestamp, self.humidityMin*random.random()) self.addValue(RMParser.dataType.MAXRH, startDayTimestamp, self.humidityMax*random.random()) if self.parserDebug: log.debug(self.result)
def perform( self): # The function that will be executed must have this name if self.params['stationID']: stationID = self.params['stationID'] else: log.error("*** No Station ID") self.lastKnownError = "No Station ID" #NOAA has a bunch of different feeds for the weather data, but only obhistory has rainfall # A full listing of stations/urls can be found here: https://w1.weather.gov/xml/current_obs/index.xml stationURL = "https://w1.weather.gov/data/obhistory/" + stationID + ".html" self.params['_stationURL'] = stationURL # downloading data from a URL convenience function since other python libraries can be used self.getObservations(stationURL) if self.parserDebug: log.debug(self.result)
def getDayGlobalRestriction(self, timestamp, ignoreFreezeProtect=False): # Cyclic import workaround from RMDataFramework.rmMainDataRecords import RMZoneWateringFlag if self.isInMonthRestriction(timestamp): return RMZoneWateringFlag.zwfRestrictionMonth if self.isInDayRestriction(timestamp): return RMZoneWateringFlag.zwfRestrictionDay if self.getRainDelayRestriction(timestamp) > 0: log.debug("Restricted for rain delay") return RMZoneWateringFlag.zwfRestrictionRainDelay if not ignoreFreezeProtect and self.isInFreezeProtect(timestamp): return RMZoneWateringFlag.zwfRestrictionFreezeProtect return RMZoneWateringFlag.zwfNormal
def isInFreezeProtect(self, timestamp): if self.globalRestrictions.useFreezeControlTemp: dayMinTemp = self.__dayMinTemperature.get( rmGetStartOfDay(timestamp), None) if dayMinTemp is None: log.debug( "No minimum temperature for %d found, won't restrict." % rmGetStartOfDay(timestamp)) return False if int(dayMinTemp) <= int( self.globalRestrictions.minFreezeControlTemp): log.debug("Restricted for minimum temperature %s <= %s" % \ (`dayMinTemp`, `self.globalRestrictions.minFreezeControlTemp`)) return True return False
def installParser(self, tempFilePath, fileName): filePath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "parsers", fileName)) shutil.move(tempFilePath, filePath) try: module = imp.load_source(fileName, filePath) log.info(" * Parser %s successful loaded from file '%s'" % (fileName, filePath)) parser = RMParser.parsers[-1] # Last added parser enabled = parser.isEnabledForLocation(globalSettings.location.timezone, \ globalSettings.location.latitude, \ globalSettings.location.longitude ) parserConfig, isNew = self.parserTable.addParser(fileName, parser.parserName, enabled, parser.params) if not isNew: params = self.parserTable.getParserParams(parserConfig.dbID) if params: parser.params = params RMParser.parsers.pop() #delete old entry pkeys = self.parsers.keys() for pkey in pkeys: if parserConfig.dbID is pkey.dbID: del self.parsers[pkey] self.parsers[parserConfig] = parser parserConfig.userDataTypes = self.userDataTypeTable.addRecords(parser.userDataTypes) self.parserUserDataTypeTable.addRecords(parserConfig.dbID, parserConfig.userDataTypes) log.debug(parserConfig) return True except Exception as e: try: if os.path.exists(filePath): os.remove(filePath) except Exception, e: log.exception(e) log.error(" * Error installing/loading parser %s from file '%s'" % (fileName, filePath)) log.exception(e)
def __refreshWIFI(self): timestamp = rmCurrentTimestamp() lastWIFICheckTimestamp = globalWIFI.wifiInterface.lastWIFICheckTimestamp oldIP = globalWIFI.wifiInterface.ipAddress if lastWIFICheckTimestamp is None or oldIP is None or (timestamp - lastWIFICheckTimestamp) >= self.__wifiRefreshTimeout: try: globalWIFI.detect() if oldIP != globalWIFI.wifiInterface.ipAddress: log.info("Refreshed WIFI Information. (old: %s new ip: %s)" % (`oldIP`, `globalWIFI.wifiInterface.ipAddress`)) if RMOSPlatform().AUTODETECTED == RMOSPlatform.ANDROID: return # Handle None IP if globalWIFI.wifiInterface.ipAddress is None: if self.__lastNoneIpTimestamp is None or (timestamp - self.__lastNoneIpTimestamp) < self.__wifiNoneIpTimeout: # First occurrence of None IP OR we can wait some more time. if self.__lastNoneIpTimestamp is None: self.__lastNoneIpTimestamp = timestamp log.debug("Refreshed WIFI Information - no IP detected. Give it some more time: %d seconds!" % (self.__wifiNoneIpTimeout - (timestamp - self.__lastNoneIpTimestamp), )) return else: globalWIFI.restart() log.warn("Refreshed WIFI Information - WIFI quick reloaded because no IP detected. New IP is %s" % `globalWIFI.wifiInterface.ipAddress`) self.__lastNoneIpTimestamp = None # Reset None IP timestamp. # Check if we never connected to this AP, set back AP mode and restart app if globalWIFI.wifiInterface.mode == "managed" and not globalWIFI.hasConnectedOnce(): if globalWIFI.wifiInterface.hasClientLink: globalWIFI.saveHasConnectedOnce(True) else: log.warning("WIFI Watcher Client IP (%s) configuration failed, restarting in AP mode." % oldIP) globalWIFI.setDefaultAP() globalWIFI.saveHasConnectedOnce(False) globalWIFI.restart() self.__mainManager.touchWakeMessage() except Exception, e: log.error(e)
def __getSolarRadiation(self): historyForecast = self.jsonResponse["history"]["observations"] if historyForecast is None: log.debug("No hourly forecast found for solar radiation") return arrSR = [] arrT = [] for obsdict in historyForecast: instantSr = self.__toFloat(obsdict["solarradiation"]) if instantSr is None: log.debug("Invalid solar radiation value found in forecast") return arrSR.append(instantSr) hour = self.__toInt(obsdict["date"]["hour"]) min = self.__toInt(obsdict["date"]["min"]) mm = hour*60 + min arrT.append(mm) #computing solar energy per minute (measurement unit = W*min*m-2) solarRadEnergy = 0 for i in range(0, len(arrSR)): dt = arrT[i] if(i>0): dt -= arrT[i-1] solarRadEnergy += dt * arrSR[i] #converting to W*h*m-2 solarRadEnergy = solarRadEnergy / 60 #converting to MJ*m-2 solarRadEnergyMJ = solarRadEnergy * 3.6 /1000 #time utc jutc = self.jsonResponse["history"]["utcdate"] yyyy = self.__toInt(jutc["year"]) mm = self.__toInt(jutc["mon"]) dd = self.__toInt(jutc["mday"]) hour = self.__toInt(jutc["hour"]) mins = self.__toInt(jutc["min"]) dd = datetime.datetime(yyyy, mm, dd, hour, mins) timestamp = calendar.timegm( dd.timetuple()) self.addValue(RMParser.dataType.SOLARRADIATION, timestamp, solarRadEnergyMJ)
def perform(self): days = self.params["historicDays"] intervals = days / self.maxAllowedDays + (days % self.maxAllowedDays != 0) lastIntervalStartDay = datetime.date.today() if intervals > 1: days = self.maxAllowedDays log.debug("Days: %d Intervals: %d" % (days, intervals)) for i in range(0, intervals): startDay = lastIntervalStartDay - datetime.timedelta(days=1) #CIMIS real data starts from yesterday endDay = startDay - datetime.timedelta(days=(days + 1)) lastIntervalStartDay = endDay try: log.debug("Running CIMIS for startDay: %s endDay: %s" % (startDay, endDay)) self.__retrieveData(endDay, startDay) # we call with startDay/endDay swapped because CIMIS expects historic intervals except Exception, e: log.error("*** Error running cimis parser") log.exception(e)
def preRun(self): unmixedForecastAvailable = False lastForecast = None latestForecastByParser = self.parserDataTable.getLastForecastByParser() for parserID in latestForecastByParser: parserConfig = self.findParserConfig(parserID) if parserConfig != None: parserConfig.runtimeLastForecastInfo = latestForecastByParser[parserID] if not parserConfig.runtimeLastForecastInfo.processed: unmixedForecastAvailable = True if lastForecast == None: lastForecast = parserConfig.runtimeLastForecastInfo log.debug("*** All values are already mixed! No need to run the Mixer!") for parserConfig in self.parsers: self.parserDataTable.clearHistory(parserConfig.dbID, False) globalDbManager.parserDatabase.commit() globalDbManager.parserDatabase.vacuum() return None, None
def __diagNetwork(self): try: with open("/proc/net/route") as f: for line in f: fields = line.strip().split() if fields[1] != "00000000": # default gateway destination 0.0.0.0 continue #log.debug(fields) if int(fields[3], 16) & 2: # check route to be UG from the third field which is in base16 self.__networkStatus = True try: self.__networkGateway = socket.inet_ntoa(struct.pack("=L", int(fields[2], 16))) #self.__networkGateway = ".".join([str(int(fields[2][i:i+2], 16)) for i in range(0, len(fields[2]), 2)]) # depends on endianess except: self.__networkGateway = None log.debug("Cannot get gateway address.") log.debug("Network gateway (%s) up on interface %s" % (self.__networkGateway, fields[0])) return except: log.error("Cannot find /proc entry for network diag") self.__networkStatus = False