from pyowm import OWM from pyowm.utils import config from pyowm.utils.config import get_config_from from pyowm.utils import timestamps config_dict = config.get_default_config_for_subscription_type('professional') owm = OWM('ввести код полученный на сайте https://openweathermap.org/', config_dict) owm.supported_languages config_dict['language'] = 'ru' mgr = owm.weather_manager() #place = input("Ваше местоположение(city, country): ") observation = mgr.weather_at_place('Vitebsk, BY') reg = owm.city_id_registry() list_of_locations = reg.locations_for('Vitebsk', country='BY') vitebsk = list_of_locations[0] lat = vitebsk.lat lon = vitebsk.lon #daily_forecast = mgr.forecast_at_place('Vitebsk,BY', 'daily').forecast w = observation.weather print(f'Витебск. Долгота: {lat} Широта: {lon}') #print(w.temperature('celsius'), w.detailed_status, w.wind(), w.rain, w.clouds, w.humidity, w. heat_index) print('Сейчас: ' + str(w.detailed_status)) print('Температура: ' + str(w.temperature('celsius'))) #print('Ощущается: ' + str(w. heat_index)) print('Ветер:' + str(w.wind()))
from pyowm import OWM # Setting up owm object with my API key api_key = "b3d67d6ef220e7bfe7f6e4fb688940d3" owm_obj = OWM(api_key) # Searching for Lund, Sweden with the registry reg = owm_obj.city_id_registry() cities_found = reg.ids_for('Lund', country='SE') # Setting the observation object to Lund and collecting weather data obs_obj = owm_obj.weather_at_id(cities_found[0][0]) weather = obs_obj.get_weather() # Creating forecast object fc = owm_obj.three_hours_forecast_at_id(cities_found[0][0]) print(fc.will_have_sun()) # Getting the daily forecast for Lund, Sweden # daily_forecast = owm_obj.daily_forecast_at_id(cities_found[0][0]) # print(daily_forecast)
class NeoPixelForecast(NeoPixelMultiBase): __version__ = 0.1 __updated__ = '2019-12-29' """ STATIC CLASS ATTRIBUTES """ MODE_TODAY_DAYTIME = '1' MODE_TODAY_ALL = '2' MODE_TOMORROW_DAYTIME = '3' MODE_TOMORROW_ALL = '4' MODE_3DAYS_DAYTIME = '5' MODE_3DAYS_ALL = '6' # TODO better to have 5d forecast aggregated per day? MODE_5DAYS_DAYTIME = '7' MODE_5DAYS_ALL = '8' # WEATHER CONDITION CODE # each weather condition based on rain, cloud coverage and temperature is mapped into discrete number of condition states # that are indicated by different colors on the LED strip # storm: digit 6, big endian CONDITION_STORM = 0x40 # snow: digit 5, big endian CONDITION_SNOW = 0x20 # temperature: digit 4-3, big endian CONDITION_LTMP = 0x08 CONDITION_MTMP = 0x10 CONDITION_HTMP = 0x18 # rain/cloud: digit 2-0, big endian CONDITION_CLEAR = 0x01 CONDITION_SLCLO = 0x02 CONDITION_CLO = 0x03 CONDITION_SLRAI = 0x04 CONDITION_RAI = 0x05 """ OBJECT ATTRIBUTES """ owm = None # geo coordinates for desired location cityID = 0 cityName = None cityCountry = None cityLon = 0.0 cityLat = 0.0 # winter mode will adapt the adapt the temperature scale, e.g. >10C is considered high temperature in winter # winterConf will enable winterMode determination based on properties file definition winterConf = False # winterMode is the mode dependent on the time of the year winterMode = False # sampleboard storing currently displayed weather conditions # a dictionary consisting of {<id> : {"timestamp", "color", "CATAcode", "OWMcode", "temp", "cloud", "rain", "debug"}, ...} __sampleboard = None """ TODO adapt config to Forecast requirement constructor for multi strip base class multiple strips connected to different GPIO pins will be treated as a chain of strips attached to each other. if first strip is filled up, second one will be filled with the remaining buffer content and so on. configuration for the strips is taken from a property file that needs to be defined. format of the property file is expected to be: [GeneralConfiguration] Brightness=0.3 [Strip1] PixelPin1=D18 PixelNum1=60 PixelOrder1=GRBW [Strip2] PixelPin2=D21 PixelNum2=301 PixelOrder2=GRB [Strip3] PixelPin3=D13 PixelNum3=145 PixelOrder3=GRB :param color_schema: the color schema class which defined the color values, e.g. NeoPixelColors or derived classes :type color_schema: class """ def __init__(self, color_schema): super().__init__(color_schema) config = Configurations() #get non OWM specific properties self.winterConf = config.isWinterMode() #init OWM registration self.__init_OWM(config) ######################################## # UTILITY METHODS # ######################################## """ reads forecast config values from the defined property file this will instantiate the OpenWeatherMap instance and read country, city, ... data property file consists of two sections: - [OWMData]:APIKeyDomain, APIKeyName(optional), APIKey - [ApplicationData]:CityID, CityName, Country """ def __init_OWM(self, config): #get your personal key apiKey = config.getOWMKey() if apiKey is None: raise RuntimeError( 'You need to define an Open Weather Map API key to run the forecast module!' ) #get location for request #TODO get location via IP: https://ipinfo.io/developers self.cityLon = config.getLongitude() self.cityLat = config.getLatitude() self.cityID = config.getCityID() self.cityName = config.getCityName() self.cityCountry = config.getCityCountry() #initiate OpenWeatherMap object self.owm = OWM(apiKey) reg = self.owm.city_id_registry() #check whether we can get get lon/lat and id based on cityName and cityCountry if self.cityName is not None and self.cityCountry is not None: if self.cityLat is None or self.cityLon is None: try: locs = reg.locations_for(self.cityName, self.cityCountry, matching='exact') #always select first from list loc = locs.pop(0) self.cityID = int(loc[0]) self.cityLon = float(loc[2]) self.cityLon = float(loc[3]) except (ValueError, IndexError): pass else: # fallback to location determined by external IP of Raspberry self.cityName = self.localCity self.cityCountry = self.localCountry self.cityLat = self.localLat self.cityLon = self.localLon # final try to get city id for defined location if self.cityID is None: try: locs = reg.ids_for(self.cityName, self.cityCountry, matching='exact') #always select first from list loc = locs.pop(0) self.cityID = int(loc[0]) except (ValueError, IndexError): pass if self.cityID is None and self.cityLat == self.cityLon == None: raise RuntimeError('Defined city could not be found: {0}'.format( self.cityName)) ######################################## # COLOR SCALE METHODS # ######################################## """ fills weather forecast data based on defined mode OWM weather API reference: https://github.com/csparpa/pyowm/blob/a5d8733412168516f869c84600812e0046c209f9/sphinx/usage-examples-v2/weather-api-usage-examples.md :param color_mode: forecast period to be display, see MODE_TODAY, MODE_TOMORROW_DAYTIME, MODE_ALL, ... :type color_mode: str """ def fillStrips(self, color_mode='2'): print("#### " + str(datetime.now()) + " Updating weather information") #request forecast #https://pyowm.readthedocs.io/en/latest/usage-examples-v2/weather-api-usage-examples.html#getting-weather-forecasts try: if self.cityLat is not None and self.cityLon is not None: forecast = self.owm.three_hours_forecast_at_coords( float(self.cityLat), float(self.cityLon)) else: forecast = self.owm.three_hours_forecast_at_id(self.cityID) except (APIInvalidSSLCertificateError): # network temporarily not available print('Network error during OWM call') # stop processing here return # create sampleboard dictionary for current weather condition sampleboard = {} # calculate offset for current days, forecast is provided in 3 hour blocks # TODO this requires adaption to timezone of defined location, current implementation considers local timezone! offset = int(forecast.when_starts('date').hour / 3) # mask for period selection, always representing full days including today, stored in big endian representation mask = 0 # position marker representing current index in binary representation for comparison with mask pos = 1 if color_mode == type(self).MODE_TODAY_DAYTIME: # masks 6am to 9pm slot the next day mask = 0x7C elif color_mode == type(self).MODE_TODAY_ALL: # masks all forecast blocks from 0am to 11:59pm the next day mask = 0xFF elif color_mode == type(self).MODE_TOMORROW_DAYTIME: # masks 6am to 9pm slot the next day mask = 0x7C00 elif color_mode == type(self).MODE_TOMORROW_ALL: # masks all forecast blocks from 0am to 11:59pm the next day mask = 0xFF00 elif color_mode == type(self).MODE_3DAYS_DAYTIME: # masks 6am to 9pm slot all next 3 days including today mask = 0x7C7C7C elif color_mode == type(self).MODE_3DAYS_ALL: # masks all forecast blocks from 0am to 11:59pm the next 3 day including today mask = 0xFFFFFF elif color_mode == type(self).MODE_5DAYS_DAYTIME: # masks 6am to 9pm slot all next 5 days including today mask = 0x7C7C7C7C7C elif color_mode == type(self).MODE_5DAYS_ALL: # just everything... mask = 0xFFFFFFFFFF # prepare position marker to current time of the day pos = pos << offset # check whether winterMode was configured in properties if self.winterConf: # winterMode shall be activated based on winter-/summertime self.winterMode = not (is_dst(timezone=self.localTimeZone)) # track current date & time of forecast cdate = forecast.when_starts('date') index = 0 # iterate through weather forecast blocks for weather in forecast.get_forecast(): # check whether current position marker matches with flagged timeslots if (mask & pos) > 0: # get 3-byte or 4-byte color representation based on weather condition sampleboard.update({ index: self.mapWeatherConditions( weather.get_temperature(unit='celsius')['temp'], weather.get_clouds(), 0 if len(weather.get_rain()) == 0 else list(weather.get_rain().values())[0], cdate, weather.get_weather_code(), len(weather.get_snow()) > 0, weather.get_wind()['speed'], weather.get_humidity(), weather.get_pressure()['press']) }) # count the number of entries for index of dictionary - dictionary is not in chronological order index = index + 1 # switch to next forecast block pos = pos << 1 cdate = cdate + timedelta(hours=3) # prepare mask for day turn analysis by shifting by the offset mask = (mask >> offset) & 0xFFFFFFFFFF # display weather forecast on LED strip self.setPixelBySampleboard(sampleboard, mask) # store currently displayed weather condition for external status requests self.__sampleboard = sampleboard """ fills the strips according to a list of color values in case there are blocks in the sampleboard that shall be separated, a mask can be provided. each entry in the sampleboard must be represented by a binary 1. the block size is defined by the number of binary 1s that are in a chain without a binary 0 in between. a new block can start with a binary 0 in between. the logic for the blocks resulted from the forecast functionality, in which only certain periods of the day were taken over into sampleboard. TODO the implementation of divider needs refactoring, simplifying coding and also considering cases where full day is considered in bit mask but still there should be a day divider being shown TODO implement blinking indication for storm and extreme weather situations :param sampleboard: TODO UPDATE DESCRIPTION BASED ON CHANGED STRUCTURE list of color values defining the section, the section size depends on the number of pixels available in total :type sampleboard: list :param mask: a binary list, indicating each sampleboard entry by a binary 1 and each block being separated by a binary 0 in between. :type mask: long int """ def setPixelBySampleboard(self, sampleboard, mask=-1): # do nothing if sampleboard is empty if len(sampleboard) == 0: return # check if a color block mask was provided # set with all individual block lengths, the total number of dividers and divider length in relation to strip length block_set = () divider_size = 0 # a color block may indicate block in the sampleboard belonging together # these may be separated by a divider (black leds) if mask > 0: # convert mask into a set of bit values mask_set = numberToBase(mask, 2) # boolean indicator of blocks new_block = False old_block = False # counts the length of the individual blocks block_counter = 0 # check each bit in mask for block belonging together and count all blocks of '1's assembled together # a '0' in between indicates that a divider is required for i in reversed(range(len(mask_set))): if mask_set[i] == 1: new_block = True elif mask_set[i] == 0: new_block = False # check if we found a new block if new_block == True and old_block == False: # store the previous block size # we are only interested in the previous block if there is another block to follow if block_counter > 0: block_set = block_set + (block_counter, ) # start counting the next block block_counter = 1 # check if we are within a block elif new_block == old_block == True: block_counter = block_counter + 1 # keep status of this cycle for analysis in next cycle old_block = new_block # check if the strip offers enough space for showing dividers # 1% of the strip length shall be reserved for dividers divider_size = int(self.getNumPixels() * 0.01) # at least 1 pixel per divider is required if len(block_set) == 0 or divider_size == 0: # reset block set if strip is too short block_set = () divider_size = 0 #print("mask: " + str(mask_set) + " block_set: " + str(block_set) + " divider size: " + str(divider_size)) # divide the sections across all strips by the number of color entries in the sampleboard sectionsize = int(self.getNumPixels() / len(sampleboard)) # preset pixel colors for pixelindex in range(self.getNumPixels() - 1): # fill up remaining pixels if (int(pixelindex / sectionsize) >= len(sampleboard)): # get color value from sampleboard - 1. step: get the right index, 2. step get color value self.setPixel(pixelindex, sampleboard[len(sampleboard) - 1]['color']) # preset pixel colors according to color space set else: # sums up the length of the individual blocks block_counter = 0 # counts the number of the dividers for the given pixelindex divider_required = False # iterate the set of individual block sets for i in range(len(block_set)): # count how the number of sampleboard indexes covered so far block_counter = block_counter + block_set[i] # check if current sampleboard index is matching given block end if int(pixelindex / sectionsize) == block_counter - 1: # set marker divider_required = True break # let us steal the last pixels of the current block # TODO have a more accurate calculation by shrinking block size overall instead of stealing from the current block only if divider_required == True and ( int(pixelindex / sectionsize) + 1) * sectionsize - divider_size <= pixelindex: self.setPixel(pixelindex, ForecastNeoPixelColors.W_BLACK) #print('[' + str(pixelindex) + '] <DIVIDER>') else: # get color value from sampleboard - 1. step: get the right index, 2. step get color value self.setPixel( pixelindex, sampleboard[int(pixelindex / sectionsize)]['color']) #print('[' + str(pixelindex) + '] ' + str(sampleboard[int(pixelindex / sectionsize)])) # update color values if not done automatically self.show() """ maps weather conditions (temperature, rain and cloud) to color values For each temperature scale (low, medium, high) values for rain (prioritized over cloud) and cloudiness will be indicated see \docs\forecast\ColorScale.png for more information :param temp: temperature in Celsius :type temp: float :param cloud: percentage of cloud coverage :type cloud: float :param rain: amount of rain on mm/sqm :type rain: float :param timestamp: timestampf for the current weather forecast :type timestamp: datetime object :param OWMcode: OWM weather code - storm is not exposed via API and allows finer segregation of weather state :type OWMcode: integer :param snow: snow fall :type snow: boolean :param wind: wind speed m/s :type wind: float :param humidity: humidity in percentage :type humidity: integer :param pressure: athmosperic pressure in hPa :type pressure: float :returns: a dictionary consisting of {"timestamp", "color", "CATAcode", "OWMcode", "temp", "cloud", "rain", "debug"} """ def mapWeatherConditions(self, temp, cloud, rain, timestamp, OWMcode, snow, wind, humidity, pressure): # color value c = None # code describing weather condition as hex value code = None debug = None # highest prio - any storm or extreme weather indication # storm is not directly exposed via OWM API # see OWM API: https://github.com/csparpa/pyowm/blob/a5d8733412168516f869c84600812e0046c209f9/pyowm/weatherapi25/weather.py # see OWM code description - official page missing description for >= 900 # official description: https://openweathermap.org/weather-conditions # additional helpful documentation: https://godoc.org/github.com/briandowns/openweathermap # 202: thunderstorm with heavy rain, 212: heavy thunderstorm # 503: very heavy rain, 504: extreme rain # 711: smoke, 762: volcanic ash, 781: tornado # 900: tornado, 901: tropical storm, 902: hurricane, 906: hail # 958: gale, 959: severe gale, 960: storm, 961: violent storm, 962: hurricane if OWMcode == 202 or \ OWMcode == 212 or \ OWMcode == 503 or \ OWMcode == 504 or \ OWMcode == 711 or \ OWMcode == 762 or \ OWMcode == 781 or \ OWMcode == 900 or \ OWMcode == 901 or \ OWMcode == 902 or \ OWMcode == 906 or \ OWMcode == 958 or \ OWMcode == 959 or \ OWMcode == 960 or \ OWMcode == 961 or \ OWMcode == 962: c = ForecastNeoPixelColors.W_STORM code = type(self).CONDITION_STORM debug = "storm" # second prio - snow fall or dangerous freezing rain indication # see https://godoc.org/github.com/briandowns/openweathermap # 511: freezing rain elif snow or \ OWMcode == 511: c = ForecastNeoPixelColors.W_SNOW code = type(self).CONDITION_SNOW debug = "snow" # segregation by color range # low temp elif ((not (self.winterMode) and temp <= 10) or (self.winterMode and temp <= 0)): # highest prio - rain fall indication # rainy if rain > 2.5: c = ForecastNeoPixelColors.W_LOWTMP_RAINY code = type(self).CONDITION_LTMP | type(self).CONDITION_RAI debug = "low temp [{0} C], rainy [{1}mm/qm]".format(temp, rain) # slightly rainy elif rain > 0.3: c = ForecastNeoPixelColors.W_LOWTMP_SLRAINY code = type(self).CONDITION_LTMP | type(self).CONDITION_SLRAI debug = "low temp [{0} C], slightly rainy [{1}mm/qm]".format( temp, rain) # no rain else: # second prio - cloud coverage # cloudy if cloud > (100 * 3 / 8): c = ForecastNeoPixelColors.W_LOWTMP_CLOUDY code = type(self).CONDITION_LTMP | type(self).CONDITION_CLO debug = "low temp [{0} C], cloudy [{1}%]".format( temp, cloud) # slightly cloudy elif cloud > (100 * 1 / 8): c = ForecastNeoPixelColors.W_LOWTMP_SLCLOUDY code = type(self).CONDITION_LTMP | type( self).CONDITION_SLCLO debug = "low temp [{0} C], slightly cloudy [{1}%]".format( temp, cloud) # no clouds else: c = ForecastNeoPixelColors.W_LOWTMP code = type(self).CONDITION_LTMP | type( self).CONDITION_CLEAR debug = "low temp [{0} C]".format(temp) # mid temp elif (not (self.winterMode) and temp <= 25) or (self.winterMode and temp <= 10): # highest prio - rain fall indication # rainy if rain > 2.5: c = ForecastNeoPixelColors.W_MIDTMP_RAINY code = type(self).CONDITION_MTMP | type(self).CONDITION_RAI debug = "mid temp [{0} C], rainy [{1}mm/qm]".format(temp, rain) # slightly rainy elif rain > 0.3: c = ForecastNeoPixelColors.W_MIDTMP_SLRAINY code = type(self).CONDITION_MTMP | type(self).CONDITION_SLRAI debug = "mid temp [{0} C], slightly rainy [{1}mm/qm]".format( temp, rain) # no rain else: # second prio - cloud coverage # cloudy if cloud > (100 * 3 / 8): c = ForecastNeoPixelColors.W_MIDTMP_CLOUDY code = type(self).CONDITION_MTMP | type(self).CONDITION_CLO debug = "mid temp [{0} C], cloudy [{1}%]".format( temp, cloud) # slightly cloudy elif cloud > (100 * 1 / 8): c = ForecastNeoPixelColors.W_MIDTMP_SLCLOUDY code = type(self).CONDITION_MTMP | type( self).CONDITION_SLCLO debug = "mid temp [{0} C], slightly cloudy [{1}%]".format( temp, cloud) # no clouds else: c = ForecastNeoPixelColors.W_MIDTMP code = type(self).CONDITION_MTMP | type( self).CONDITION_CLEAR debug = "mid temp [{0} C]".format(temp) # high temp elif (not (self.winterMode) and temp > 25) or (self.winterMode and temp > 10): # highest prio - rain fall indication # rainy if rain > 2.5: c = ForecastNeoPixelColors.W_HITMP_RAINY code = type(self).CONDITION_HTMP | type(self).CONDITION_RAI debug = "high temp [{0} C], rainy [{1}mm/qm]".format( temp, rain) # slightly rainy elif rain > 0.3: c = ForecastNeoPixelColors.W_HITMP_SLRAINY code = type(self).CONDITION_HTMP | type(self).CONDITION_SLRAI debug = "high temp [{0} C], rainy [{1}mm/qm]".format( temp, rain) # no rain else: # second prio - cloud coverage # cloudy if cloud > (100 * 3 / 8): c = ForecastNeoPixelColors.W_HITMP_CLOUDY code = type(self).CONDITION_HTMP | type(self).CONDITION_CLO debug = "high temp [{0} C], cloudy [{1}%]".format( temp, cloud) # slightly cloudy elif cloud > (100 * 1 / 8): c = ForecastNeoPixelColors.W_HITMP_SLCLOUDY code = type(self).CONDITION_HTMP | type( self).CONDITION_SLCLO debug = "high temp [{0} C], slightly cloudy [{1}%]".format( temp, cloud) # no clouds else: c = ForecastNeoPixelColors.W_HITMP code = type(self).CONDITION_HTMP | type( self).CONDITION_CLEAR debug = "high temp [{0} C]".format(temp) print("weather condition: " + debug) return { "timestamp": timestamp.ctime(), "color": c, "CATAcode": code, "OWMcode": OWMcode, "temp": temp, "cloud": cloud, "rain": rain, "wind": wind, "humidity": humidity, "pressure": pressure, "debug": debug } ######################################## # GETTER/SETTER METHODS # ######################################## """ returns currently displayed weather condition :returns: dictionary consisting of {<id> : {"timestamp", "color", "CATAcode", "OWMcode", "temp", "cloud", "rain", "debug"}, ...} """ def getCurrentWeatherCondition(self): return self.__sampleboard
def weather_data(city, country_code): try: owm = OWM("c7944fb01f126e8605540d01be0dc854") except: print("there was problem with the token") return registry = owm.city_id_registry() list_of_cities = registry.ids_for(city) # get the desired city code for item in list_of_cities: if item[2] == country_code: city_code = item[0] break else: print(f"there is no {city} in {country_code} ") return w_manager = owm.weather_manager() try: weather = w_manager.weather_at_place(f'{city}, {country_code}').weather except: print("there was an error retrieving the data ") temp = weather.temperature('celsius')["temp"] sunrise_time = weather.sunrise_time(timeformat='date') sunset_time = weather.sunset_time(timeformat='date') wind = weather.wnd # dict {speed, deg} forecast = w_manager.forecast_at_id(city_code, "3h") print(f""" Today weather in {city},{country_code} is: temp :{temp} celsius sunrise_time:{sunrise_time} sunset_time :{sunset_time} wind :{wind["speed"]}kmh, {wind["deg"]} deg' """) # polution data # first get the coordinates city_location = registry.locations_for(city, country=country_code) city_lat = city_location[0].lat city_lon = city_location[0].lon # # coi = owm.coindex_around_coords(city_lat, city_lon) # coi = owm.airpollution_manager().coindex_around_coords(city_lat, city_lon) # # print(coi) # calculate data for humidity plot forcasted_weather = [] set_of_dates = [] # get data from the forecast object for item in forecast.forecast.weathers: # format date string for printing (DD/MM) forecast_date = str(datetime.fromtimestamp( item.ref_time).day) + "/" + str( datetime.fromtimestamp(item.ref_time).month) # create list of tuple with data (humidity level, date) forcasted_weather.append([item.humidity, forecast_date]) # create set of dates, because the date strings are not sortable, the "set" is created manually if not forecast_date in set_of_dates: set_of_dates.append(forecast_date) print(set_of_dates) # calculate average humidity level for each day avg_humidty_lvls = [] for item in set_of_dates: list_to_calc_avg = [x[0] for x in forcasted_weather if x[1] == item] avg_humidty_lvls.append( round(sum(list_to_calc_avg) / len(list_to_calc_avg), 2)) print(avg_humidty_lvls) for x in forcasted_weather: print(x) plt.bar(set_of_dates, avg_humidty_lvls, align="center") plt.xlabel("Dates") plt.ylabel("Humidity Levels (%)") plt.title("Humidity Forecast") plt.show()
class Weather(ModuleBase): ## # @copydoc sdk::ModuleBase::moduleInit # def moduleInit(self, dictModCfg=None, dictCfgUsr=None): # Verfügbare Einstellungen mit Default-Werten festlegen dictSettings = { "lnkLocation" : "", "strLocation" : "", "nCityID" : 0, "strLanguage" : "de", "strVersion" : "2.5", "strApiKey" : "", "strReferenceTime" : "", "strRequestedTime" : "", "fTemperature" : 0.0, "fTemperatureMin" : 0.0, "fTemperatureMax" : 0.0, "strRainVolume" : "", "strSnowVolume" : "", "nWindDirection" : 0, "fWindSpeed" : 0.0, "fPressure" : 0.0, "fPressureSeaLevel" : 0.0, "nCloudCoverage" : 0, "nHumidity" : 0, "nWeatherCode" : 0, "strStatus" : "", "strStatusDetailed" : "", "strTimeSunrise" : "", "strTimeSunset" : "", "strWeatherIconUrl" : "", } self.m_strSetupApiKeyToken = uuid.uuid4().hex self.m_strSetupSearchToken = uuid.uuid4().hex self.m_strSetupCityIdToken = uuid.uuid4().hex # Vorbelegung der Moduleigenschaften mit Default-Werten, sofern noch nicht verfügbar if (not dictModCfg): dictModCfg.update(dictSettings) else: # Zurücklesen der gespeicherten Konfiguration in eigene OrderedDict dictSettings.update(dictModCfg) # Zurücksetzen des gespeicherten OrderedDict dictModCfg.clear() # Gespeichertes OrderedDict entsprechend der Sortierungsreihenfolge initialisieren dictModCfg.update(dictSettings) # for (strName, strValue) in dictSettings.items(): # if strName not in dictModCfg: # dictModCfg.update({strName : strValue}) # Beschreibung der Konfigurationseinstellungen dictCfgUsr.update({ "properties" : [ "lnkLocation", "strLocation", "nCityID", "strLanguage", "strVersion", "strApiKey", "strReferenceTime", "strRequestedTime", "fTemperature", "fTemperatureMin", "fTemperatureMax", "strRainVolume", "strSnowVolume", "nWindDirection", "fWindSpeed", "fPressure", "fPressureSeaLevel", "nCloudCoverage", "nHumidity", "nWeatherCode", "strStatus", "strStatusDetailed", "strTimeSunrise", "strTimeSunset", "strWeatherIconUrl", ], "strReferenceTime" : { "title" : "Zeitstempel Wetterdaten", "default" : "", "readonly" : True, }, "strRequestedTime" : { "title" : "Letzte Aktualisierung", "default" : "", "readonly" : True, }, "fTemperature" : { "title" : "Aktuelle Temperatur", "default" : "", "readonly" : True, }, "fTemperatureMin" : { "title" : "Minimal-Temperatur", "default" : "", "readonly" : True, }, "fTemperatureMax" : { "title" : "Maximal-Temperatur", "default" : "", "readonly" : True, }, "strRainVolume" : { "title" : "Regen-Volumen", "default" : "", "readonly" : True, }, "strSnowVolume" : { "title" : "Schnee-Volumen", "default" : "", "readonly" : True, }, "nWindDirection" : { "title" : "Windrichtung", "default" : "", "readonly" : True, }, "fWindSpeed" : { "title" : "Windgeschwindigkeit", "default" : "", "readonly" : True, }, "fPressure" : { "title" : "Luftdruck", "default" : "", "readonly" : True, }, "fPressureSeaLevel" : { "title" : "Luftdruck auf Meereshöhe", "default" : "", "readonly" : True, }, "nCloudCoverage" : { "title" : "Bewölkungsgrad", "default" : "", "readonly" : True, }, "nHumidity" : { "title" : "Luftfeuchtigkeit", "default" : "", "readonly" : True, }, "nWeatherCode" : { "title" : "Wetterkennung", "default" : "", "readonly" : True, }, "strStatus" : { "title" : "Wetterstatus", "default" : "", "readonly" : True, }, "strStatusDetailed" : { "title" : "Detailierter Wetterstatus", "default" : "", "readonly" : True, }, "strTimeSunrise" : { "title" : "Sonnenaufgang", "default" : "", "readonly" : True, }, "strTimeSunset" : { "title" : "Sonnenuntergang", "default" : "", "readonly" : True, }, "strWeatherIconUrl" : { "title" : "URL für Wettersymbol", "default" : "", "readonly" : True, }, "strApiKey" : { "title" : "OpenWeatherMap API Key", "description" : ("Ein kostenloser OpenWeatherMap.org API Key wird benötigt, um die Wetterinformationen abrufen zu können."), "default" : "", "readonly" : True, }, "strLocation" : { "title" : "Ort", "description" : ("Die Wetterinformationen werden für diesen Ort abgerufen."), "default" : "", "readonly" : True, }, "nCityID" : { "title" : "City-ID", "description" : ("City-ID des Orts, für den Wetterinformationen abzurufen sind."), "default" : 0, "readonly" : True, }, "lnkLocation" : { "title" : "Wettervorhersage", "description" : ("Einrichten"), "default" : "/modules/Weather.html", "showlink" : True }, "strLanguage" : { "title" : "Sprache", "description" : ("Angabe der Sprache, in der die Wetterinformationen bereitzustellen sind."), "default" : "", "choices" : { "Arabic" : "ar", "Bulgarian" : "bg", "Catalan" : "ca", "Czech" : "cz", "German" : "de", "Greek" : "el", "English" : "en", "Persian (Farsi)" : "fa", "Finnish" : "fi", "French" : "fr", "Galician" : "gl", "Croatian" : "hr", "Hungarian" : "hu", "Italian" : "it", "Japanese" : "ja", "Korean" : "kr", "Latvian" : "la", "Lithuanian" : "lt", "Macedonian" : "mk", "Dutch" : "nl", "Polish" : "pl", "Portuguese" : "pt", "Romanian" : "ro", "Russian" : "ru", "Swedish" : "se", "Slovak" : "sk", "Slovenian" : "sl", "Spanish" : "es", "Turkish" : "tr", "Ukrainian" : "ua", "Vietnamese" : "vi", "Chinese Simplified" : "zh_cn", "Chinese Traditional" : "zh_tw" } }, "strVersion" : { "title" : "Version", "description" : ("Optionale Angabe einer Version des zu verwendenden APIs zum Abrufen der Wetterinformationen."), "default" : "2.5", }, }) # Auslesen der aktuellen Konfigurationseinstellungen self.m_strApiKey = globs.getSetting("Weather", "strApiKey", r".+", "") self.m_strLangID = globs.getSetting("Weather", "strLanguage", r"[a-z]{2}(_[a-z]{2})?", "de") self.m_strLocation = globs.getSetting("Weather", "strLocation", r".+", "") self.m_strVersion = globs.getSetting("Weather", "strVersion", r"[0-9]+\.[0-9]+", "2.5") self.m_nCityID = globs.getSetting("Weather", "nCityID", "[0-9]+", 0) self.m_oWeatherApi = None self.m_oObservation = None self.m_oWeather = None self.createWeatherApiObjects() self.m_lstCityIDs = [] self.m_oTaskFindCityIDsForLocation = None self.m_nLastTemperature = None self.m_nLastWeatherCondition = None return True def createWeatherApiObjects(self, bRenew=False): if bRenew: self.m_oObservation = None self.m_oWeather = None self.m_oWeatherApi = None if (self.m_strApiKey and (not self.m_oWeatherApi)): self.m_oObservation = None self.m_oWeather = None self.m_oWeatherApi = OWM( API_key=self.m_strApiKey, language=self.m_strLangID, version=self.m_strVersion) if (self.m_oWeatherApi and self.m_nCityID and (not self.m_oObservation)): self.m_oWeather = None self.m_oObservation = self.m_oWeatherApi.weather_at_id(self.m_nCityID) if (self.m_oObservation and not self.m_oWeather): self.m_oWeather = self.m_oObservation.get_weather() return ## # @brief Brief # # @param [in] self Parameter_Description # @return Return_Description # # @details Details # def moduleExit(self): print("%r::moduleExit()" % (self)) return True #============================================================================== # moduleWidget #============================================================================== def moduleWidget(self): pass ## # @brief Ausführung der Modulaktion. # # @param [in] self Objektinstanz # @param [in] strPath die angeforderte Pfadangabe # @param [in] oHtmlPage die zu erstellende HTML-Seite # @param [in] dictQuery Dictionary der angeforderten Parameter und Werte als Liste # @param [in] dictForm Dictionary der angeforderten Formularparameter und Werte als Liste # @return # Liefert True, wenn die Aktion erfolgreich ausgeführt werden konnte oder # False im Falle eines Fehlers. # # @details Details # def moduleExec(self, strPath, oHtmlPage, dictQuery, dictForm ): print("%r::moduleExec(strPath=%s, oHtmlPage=%s, dictQuery=%r, dictForm=%r)" % ( self, strPath, oHtmlPage, dictQuery, dictForm)) if (re.match(r"/modules/Weather\.html", strPath) and (not oHtmlPage == None)): return self.serveHtmlPage(oHtmlPage, dictQuery, dictForm) if (not dictQuery): return False for (strCmd, lstArg) in dictQuery.items(): # Moduleinstellungen wurden geändert if (strCmd == "settings" and lstArg and "Weather" in lstArg): for (strCmd, _) in dictForm.items(): if (strCmd in ["strLanguage", "strVersion"]): self.createWeatherApiObjects(bRenew=True) continue continue # Systemeinstellungen wurden geändert if (strCmd == "system"): if ("date" in lstArg or "time" in lstArg): self.checkWeather() continue continue # Timer-Ereignisse if (strCmd == "timer"): if ("cron" in lstArg): self.checkWeather() continue continue bResult = False # Unbekanntes Kommando return bResult def checkWeather(self): try: strRequestedTime = globs.getSetting("Weather", "strRequestedTime", ".+", "") bRenew = (((int(time.strftime("%M")) % 15) != 0) or (not strRequestedTime)) self.createWeatherApiObjects(bRenew=bRenew) if (not self.m_oWeather): return strRequestedTime = time.strftime("%Y-%m-%d %H:%M:%S") strReferenceTime = self.m_oWeather.get_reference_time(timeformat='iso')[:-3] dictData = self.m_oWeather.get_temperature(unit="celsius") globs.dbg("Temperature information %r" % (dictData)) fTemperature = float(dictData["temp"]) if "temp" in dictData and dictData["temp"] else -999.9 fTemperatureMin = float(dictData["temp_min"]) if "temp_min" in dictData and dictData["temp_min"] else -999.9 fTemperatureMax = float(dictData["temp_max"]) if "temp_max" in dictData and dictData["temp_max"] else -999.9 dictData = self.m_oWeather.get_wind() globs.dbg("Wind information %r" % (dictData)) nWindDirection = int(dictData["deg"]) if "deg" in dictData and dictData["deg"] else -999 fWindSpeed = float(dictData["speed"]) if "speed" in dictData and dictData["speed"] else -999.9 dictData = self.m_oWeather.get_pressure() globs.dbg("Atmospharic pressure information %r" % (dictData)) fPressure = float(dictData["press"]) if "press" in dictData and dictData["press"] else -999.9 fPressureSeaLevel = float(dictData["sea_level"]) if "sea_level" in dictData and dictData["sea_level"] else -999.9 dictData = self.m_oWeather.get_rain() globs.dbg("Rain volume information %r" % (dictData)) strRainVolume = "" for (strTime, nVolume) in dictData.items(): strRainVolume += ", " if strRainVolume else "" strRainVolume += "%s: %s" % (strTime, nVolume) dictData = self.m_oWeather.get_snow() globs.dbg("Snow volume information %r" % (dictData)) strSnowVolume = "" for (strTime, nVolume) in dictData.items(): strSnowVolume += ", " if strSnowVolume else "" strSnowVolume += "%s: %s" % (strTime, nVolume) nCloudCoverage = self.m_oWeather.get_clouds() nHumidity = self.m_oWeather.get_humidity() nWeatherCode = self.m_oWeather.get_weather_code() strStatus = self.m_oWeather.get_status() strStatusDetailed = self.m_oWeather.get_detailed_status() strSunriseTime = self.m_oWeather.get_sunrise_time("iso")[:-3] strSunsetTime = self.m_oWeather.get_sunset_time("iso")[:-3] strWeatherIconUrl = self.m_oWeather.get_weather_icon_url() globs.setSetting("Weather", "strRequestedTime", strRequestedTime) globs.setSetting("Weather", "strReferenceTime", strReferenceTime) globs.setSetting("Weather", "fTemperature", fTemperature) globs.setSetting("Weather", "fTemperatureMin", fTemperatureMin) globs.setSetting("Weather", "fTemperatureMax", fTemperatureMax) globs.setSetting("Weather", "strRainVolume", strRainVolume) globs.setSetting("Weather", "strSnowVolume", strSnowVolume) globs.setSetting("Weather", "nWindDirection", nWindDirection) globs.setSetting("Weather", "fWindSpeed", fWindSpeed) globs.setSetting("Weather", "fPressure", fPressure) globs.setSetting("Weather", "fPressureSeaLevel", fPressureSeaLevel) globs.setSetting("Weather", "nCloudCoverage", nCloudCoverage) globs.setSetting("Weather", "nHumidity", nHumidity) globs.setSetting("Weather", "nWeatherCode", nWeatherCode) globs.setSetting("Weather", "strStatus", strStatus) globs.setSetting("Weather", "strStatusDetailed", strStatusDetailed) globs.setSetting("Weather", "strTimeSunrise", strSunriseTime) globs.setSetting("Weather", "strTimeSunset", strSunsetTime) globs.setSetting("Weather", "strWeatherIconUrl", strWeatherIconUrl) globs.setSetting("System", "strTimeSunrise", sdk.translateStrToLocalTimeStr(strSunriseTime, "%Y-%m-%d %H:%M:%S")) globs.setSetting("System", "strTimeSunset", sdk.translateStrToLocalTimeStr(strSunsetTime, "%Y-%m-%d %H:%M:%S")) nTemperature = round(fTemperature) nWeatherCondition = self.normalizeWeatherCondition(nWeatherCode) if (not self.m_nLastWeatherCondition or not self.m_nLastTemperature or self.m_nLastWeatherCondition != nWeatherCondition or self.m_nLastTemperature != nTemperature): TaskModuleEvt(self.m_oWorker, "/int/evt.src", dictQuery={ "temperature" : ["%s" % (nTemperature)], "weather" : ["%s" % (nWeatherCondition)] } ).start() strWeatherReport = "Das aktuelle Wetter: %s bei einer Temperatur von %d Grad Celsius" % ( strStatusDetailed, nTemperature) TaskSpeak(self.m_oWorker, strWeatherReport).start() self.m_nLastTemperature = nTemperature self.m_nLastWeatherCondition = nWeatherCondition except: globs.exc("Abrufen von Wetterdaten") return ## # "sunny", # 01 - sonnig (sunny) # "cheerful", # 02 - heiter (cheerful) # "cloudy", # 03 - bewölkt (cloudy) # "covered", # 04 - bedeckt (covered) # "rainy", # 05 - regnerisch (rainy) # "changeable", # 06 - wechselhaft (changeable) # "thunderstorm", # 07 - gewittrig (thunderstorm) # "snowy", # 08 - schneeig (snowy) # "foggy", # 09 - neblig (foggy) # def normalizeWeatherCondition(self, nWeatherCode): if (nWeatherCode >= 200 and nWeatherCode < 300): # Thunderstorm -> thunderstorm return 7 if (nWeatherCode >= 300 and nWeatherCode < 400): # Drizzle -> changeable return 6 if (nWeatherCode >= 500 and nWeatherCode < 600): # Rain -> rainy return 5 if (nWeatherCode >= 600 and nWeatherCode < 700): # Snow -> snowy return 8 if (nWeatherCode >= 700 and nWeatherCode < 800): # Atmosphere -> foggy return 9 if (nWeatherCode == 800): # Clear return 1 if (nWeatherCode == 801): # Few clouds (11-25%) -> cheerful return 2 if (nWeatherCode >= 802 and nWeatherCode <= 803): # Scattered clouds (25-50%) -> cloudy # Broken clouds (51-84%) -> cloudy return 3 if (nWeatherCode == 804): # Overcast clouds (85-100%) -> covered return 4 # Default return 1 ## # @brief Bereitstellung der HTML-Seite für eine manuelle Aktualisierung. # # @param [in] self Verweis auf die eigene Instanz # @param [in] oHtmlPage Verweis auf die Instanz der HTML-Seite # @param [in] dictQuery Query-Daten # @param [in] dictForm Formulardaten # @return Liefert @c True wenn die HTML-Seite bereitgestellt werden konnte oder @c False # im Fehlerfall. # # @details Details # def serveHtmlPage(self, oHtmlPage, dictQuery, dictForm): strLocation = "" globs.log("Weather::serveHtmlPage()") try: # Formulardaten verarbeiten if (dictForm and "token" in dictForm): # Formular für API-Key gespeichert if (self.m_strSetupApiKeyToken in dictForm["token"] and "OwmApiKey" in dictForm and dictForm["OwmApiKey"][0]): self.m_strSetupApiKeyToken = uuid.uuid4().hex self.m_strApiKey = dictForm["OwmApiKey"][0] globs.setSetting("Weather", "strApiKey", self.m_strApiKey) self.m_strApiKey = globs.getSetting("Weather", "strApiKey", r".+", "") if (self.m_oWeatherApi): self.m_oWeatherApi.set_API_key(self.m_strApiKey) if (self.m_oWeatherApi and self.m_oObservation): oHtmlPage.createBox( "API-Key hinterlegen", """Der registrierte API-Key wurde erfolgreich geändert.""", strType="success", bClose=False) oHtmlPage.createButton( "OK", strClass="ym-save ym-success", strHRef="/modules/Weather.html") oHtmlPage.closeBox() return True # Formular für die Eingrenzung der Ortsnamen gespeichert elif (self.m_strSetupSearchToken in dictForm["token"] and "Location" in dictForm and dictForm["Location"][0]): self.m_strSetupSearchToken = uuid.uuid4().hex strLocation = dictForm["Location"][0] # self.m_strLocation = dictForm["Location"][0] # globs.setSetting("Weather", "strLocation", self.m_strLocation) # self.m_strLocation = globs.getSetting("Weather", "strLocation", r".+", "") # Formular für die City-ID gespeichert elif (self.m_strSetupCityIdToken in dictForm["token"] and "CityID" in dictForm and "Location" in dictForm and dictForm["CityID"][0] and dictForm["Location"][0]): self.m_strSetupCityIdToken = uuid.uuid4().hex self.m_nCityID = int(dictForm["CityID"][0]) globs.setSetting("Weather", "nCityID", self.m_nCityID) self.m_nCityID = globs.getSetting("Weather", "nCityID", "[0-9]+", 0) self.m_oObservation = None self.createWeatherApiObjects() if (self.m_oObservation): self.m_strLocation = self.m_oObservation.get_location().get_name() globs.setSetting("Weather", "strLocation", self.m_strLocation) self.m_strLocation = globs.getSetting("Weather", "strLocation", r".+", "") oHtmlPage.createBox( "Wettervorhersage für einen Ort", """Die Wettervorhersage wurde erfolgreich für den Ort %s eingerichtet.""" % ( self.m_strLocation), strType="success", bClose=False) oHtmlPage.createButton( "OK", strClass="ym-save ym-success", strHRef="/modules/Weather.html") oHtmlPage.closeBox() return True except: globs.exc("Weather: Formulardaten verarbeiten") # Weather-API Objekte anlegen self.createWeatherApiObjects() try: if (dictQuery and "Location" in dictQuery and dictQuery["Location"][0]): strLocation = dictQuery["Location"][0] # Formular für die Registrierung eines API-Key aufbauen if ((dictQuery and "token" in dictQuery and self.m_strSetupApiKeyToken in dictQuery["token"])): self.m_strSetupApiKeyToken = uuid.uuid4().hex oHtmlPage.createBox( "API-Key hinterlegen", ("""Damit die Wettervorhersage verwendet werden kann, muss ein gültiger, von OpenWeatherMap.org bezogener API-Key hinterlegt werden.""" if not self.m_strApiKey else """Der bereits hinterlegte API-Key kann jederzeit durch einen anderen, gültigen und von OpenWeatherMap.org bezogenen API-Key ersetzt werden."""), strType="info", bClose=False) oHtmlPage.openForm( dictTargets={"token" : self.m_strSetupApiKeyToken}) oHtmlPage.appendForm("OwmApiKey", strTitle="API-Key", strTip="API-Key für OpenWeatherMap.org", strInput=self.m_strApiKey, strTextType="text") oHtmlPage.closeForm(strUrlCancel="/modules/Weather.html") oHtmlPage.closeBox() return True # Formular für die Eingrenzung möglicher Orte aufbauen if ((dictQuery and "token" in dictQuery and self.m_strSetupSearchToken in dictQuery["token"])): self.m_strSetupSearchToken = uuid.uuid4().hex oHtmlPage.createBox( "Wettervorhersage für einen Ort", ("""Es wurde noch kein Ort für die Wettervorhersage festgelegt. Da die Wettervorhersage nur für bestimmte Orte zur Verfügung steht, sollte hier nach der Bezeichnung einer größeren Ortschaft oder Stadt in der näheren Umgebung gesucht werden.""" if (not self.m_strLocation) or self.m_nCityID == 0 else """Die Wettervorhersage kann jederzeit für einen anderen Ort vorgenommen werden."""), strType="info", bClose=False) oHtmlPage.openForm( dictTargets={"token" : self.m_strSetupSearchToken}) oHtmlPage.appendForm("Location", strTitle="Ortsname", strTip="Wettervorhersage für einen Ort", strInput=globs.getSetting("Weather", "strLocation", r".*", ""), strTextType="text") oHtmlPage.closeForm(strUrlCancel="/modules/Weather.html") oHtmlPage.closeBox() return True # Formular für die Auswahl einer bestimmten City-ID aufbauen if (strLocation and self.m_oWeatherApi): self.m_strSetupCityIdToken = uuid.uuid4().hex self.m_strSetupSearchToken = uuid.uuid4().hex if (not self.m_oTaskFindCityIDsForLocation): self.m_oTaskFindCityIDsForLocation = TaskDelegateLong(self.m_oWorker, self.delegateFindCityIDsForLocation, strLocation=strLocation) self.m_oTaskFindCityIDsForLocation.start() if (self.m_oTaskFindCityIDsForLocation): if (self.m_oTaskFindCityIDsForLocation.wait(0.0)): self.m_oTaskFindCityIDsForLocation = None else: oHtmlPage.createBox( "Wettervorhersage für einen Ort", """Die Wettervorhersage wird für den Ort %s geprüft. Das kann einen Moment dauern. Bitte warten...""" % ( strLocation), strType="info", bClose=False) oHtmlPage.createButton( "Abbrechen", strClass="ym-close", strHRef="/modules/Weather.html") oHtmlPage.closeBox() oHtmlPage.setAutoRefresh(nAutoRefresh=1, strUrl="/modules/Weather.html?Location=%s" % ( strLocation)) return True # oReg = self.m_oWeatherApi.city_id_registry() # lstCityIDs = oReg.ids_for(strLocation, matching="like") # [ (123, 'London', 'GB'), (456, 'London', 'MA'), (789, 'London', 'WY')] # Mehrdeutige Ergebnisse if (len(self.m_lstCityIDs) > 1): dictCityIDs = {} for oLocationTuple in self.m_lstCityIDs: dictCityIDs.update( {"%s, %s (%s)" % ( oLocationTuple[1], oLocationTuple[2], oLocationTuple[0]) : oLocationTuple[0]}) oHtmlPage.createBox( "Wettervorhersage für einen Ort", """Die Suche nach dem Ort %s hat mehrere Möglichkeiten ergeben.""" % ( strLocation), strType="info", bClose=False) oHtmlPage.openForm( dictTargets={ "token" : self.m_strSetupCityIdToken, "Location" : strLocation }) oHtmlPage.appendForm("CityID", strTitle="Ortsname", strTip="Wettervorhersage für einen Ort", strInput="%s" % (self.m_nCityID), dictChoice=dictCityIDs) oHtmlPage.closeForm(strUrlCancel="/modules/Weather.html") oHtmlPage.closeBox() return True # Eindeutiges Ergebnis if (len(self.m_lstCityIDs) == 1): self.m_nCityID = int(self.m_lstCityIDs[0][0]) globs.setSetting("Weather", "nCityID", self.m_nCityID) self.m_nCityID = globs.getSetting("Weather", "nCityID", "[0-9]+", 0) self.m_oObservation = None self.createWeatherApiObjects() if (self.m_oObservation): self.m_strLocation = self.m_oObservation.get_location().get_name() globs.setSetting("Weather", "strLocation", self.m_strLocation) self.m_strLocation = globs.getSetting("Weather", "strLocation", r".+", "") oHtmlPage.createBox( "Wettervorhersage für einen Ort", """Die Wettervorhersage wurde erfolgreich für den Ort %s eingerichtet.""" % ( self.m_strLocation), strType="success", bClose=False) oHtmlPage.createButton( "OK", strClass="ym-save ym-success", strHRef="/modules/Weather.html") oHtmlPage.closeBox() return True # Keine Ergebnisse (oder Fehler beim Anlegen des Observation-Objekts) oHtmlPage.createBox( "Wettervorhersage für einen Ort", """Für den Ort %s steht keine Wettervorhersage zur Verfügung. Vielleicht ist für eine andere größere Ortschaft oder Stadt in der näheren Umgebung eine Wettervorhersage verfügbar.""" % ( strLocation), strType="info", bClose=False) oHtmlPage.createButton( "Weiter", strClass="ym-next ym-success", strHRef="/modules/Weather.html?token=%s" % (self.m_strSetupSearchToken)) oHtmlPage.createButton( "Abbrechen", strClass="ym-close", strHRef="/modules/Weather.html") oHtmlPage.closeBox() return True except: globs.exc("Weather: Formulare aufbauen") # Default, Startseite für Einrichtung der Wettervorhersage oHtmlPage.createBox( "Wettervorhersage einrichten", """Die Wettervorhersage kann in wenigen Schritten eingerichtet werden. Für die Einrichtung ist eine Internet-Verbindung erforderlich.""", strType="info", bClose=False) # App-Key anfordern bzw. hinterlegen if (not globs.getSetting("Weather", "strApiKey", r".+", "")): self.m_strSetupApiKeyToken = uuid.uuid4().hex oHtmlPage.createText( """Derzeit ist noch kein API-Key eingestellt. Ein kostenloser API-Key kann bei OpenWeatherMap.org bezogen werden.""") oHtmlPage.createButton( "API-Key anfordern (ext)", strClass="ym-reply ym-primary", strHRef="https://openweathermap.org/price", bExternal=True) oHtmlPage.createButton( "API-Key hinterlegen", strClass="ym-edit", strHRef="/modules/Weather.html?token=%s" % (self.m_strSetupApiKeyToken)) oHtmlPage.createButton( "Abbrechen", strClass="ym-close", strHRef="/system/settings.html") oHtmlPage.closeBox() return True # City-ID einstellen if ((not self.m_strLocation) or (not self.m_oObservation)): self.m_strSetupSearchToken = uuid.uuid4().hex oHtmlPage.createText( """Derzeit ist noch kein Ort für die Wettervorhersage eingerichtet.""") oHtmlPage.openForm( dictTargets={"token" : self.m_strSetupSearchToken}) oHtmlPage.appendForm("Location", strTitle="Ortsname", strTip="Bezeichnung einer größeren Ortschaft oder Stadt in der näheren Umgebung", strInput=globs.getSetting("Weather", "strLocation", r".*", ""), strTextType="text") oHtmlPage.closeForm(strUrlCancel="/system/settings.html") oHtmlPage.closeBox() return True # Verschiedene Einstellungen vornehmen self.checkWeather() self.m_strSetupApiKeyToken = uuid.uuid4().hex self.m_strSetupSearchToken = uuid.uuid4().hex oHtmlPage.createText( "Das Wetter wird derzeit für %s vorhergesagt." % ( globs.getSetting("Weather", "strLocation", r".*", "einen namenlosen Ort") )) oHtmlPage.createButton( "Ort ändern", strClass="ym-edit", strHRef="/modules/Weather.html?token=%s" % (self.m_strSetupSearchToken)) oHtmlPage.createButton( "Schließen", strClass="ym-close", strHRef="/system/settings.html") oHtmlPage.createText("") oHtmlPage.createText( """Zusätzlich kann auch der für OpenWeatherMap.org zu verwendende API-Key verwaltet werden.""") oHtmlPage.createButton( "API-Key anfordern (ext)", strClass="ym-reply ym-primary", strHRef="https://openweathermap.org/price", bExternal=True) oHtmlPage.createButton( "API-Key hinterlegen", strClass="ym-edit", strHRef="/modules/Weather.html?token=%s" % (self.m_strSetupApiKeyToken)) oHtmlPage.closeBox() return True def delegateFindCityIDsForLocation(self, strLocation, strMatching="like"): oReg = self.m_oWeatherApi.city_id_registry() self.m_lstCityIDs = oReg.ids_for(strLocation, matching="like") # [ (123, 'London', 'GB'), (456, 'London', 'MA'), (789, 'London', 'WY')] return
class WeatherHandler: def __init__(self,OWMKEY): self.owm = OWM(OWMKEY) self.weather_dict = {} #value voor in dictionary self.temp = "" self.weather = "" self.weather_code = 0 self.prev_loc = "" ''' Description: Get weather observation from location coordinates :location: the location for the observation :obs: The weather observation ''' def getWeatherFromLoc(self,location): obs = self.owm.weather_at_coords(location["latitude"],location["longitude"]) return obs ''' Description: Get weather observation from a named place :place: the placename for the observation :obs: The weather observation ''' def getWeatherFromPlace(self,place): obs = self.owm.weather_at_place(place) return obs ''' Description: Get possible locations belonging to a placename :placename: the placename for the location list :obs: The possible locations ''' def getLocations(self,placename): reg = self.owm.city_id_registry() locations = reg.locations_for(placename) return locations ''' Description: Get weather observation from a location ID :place: the location ID :obs: The weather observation ''' def getWeatherFromID(self,location): city_id = location.get_ID() obs = self.owm.weather_at_id(city_id) return obs ''' Description: Get specific weather info for a location :placename: the placename for the weather info :weatherinfo: the type of weather info :return: The desired information ''' def get_specific_info(self,placename,infotype): return self.weather_dict[placename][infotype] ''' Description: Get an entire forecast for a place :place: the placename for the forecast :return: the forecast ''' def get_weather_forecast(self,placename): return self.weather_dict[placename] ''' Description: Add a new entry to the dictionary of weather forecasts :obs: the weather observation that should be added ''' def set_weather_forecast(self,obs): forecast = {} w = obs.get_weather() l = obs.get_location() placename = str(l.get_name()) self.prev_loc = placename forecast["wtime"] = time.asctime(time.localtime(time.time())) forecast["status"] = str(w.get_detailed_status()) forecast["temperature"] = str(w.get_temperature('celsius').get('temp')) forecast["code"] = w.get_weather_code() self.weather_dict[placename] = forecast ''' Description: Set the weather for the hometown of the bot (Nijmegen) ''' def setWeatherNimma(self): obs = self.owm.weather_at_place("Nijmegen,NL") w = obs.get_weather() self.weather = str(w.get_detailed_status()) self.temp = str(w.get_temperature('celsius').get('temp')) self.weather_code = w.get_weather_code() ''' Description: Get weather information for Nijmegen :return: Weather information for Nijmegen ''' def getWeatherNimma(self): return (self.weather,self.weather_code,self.temp) ''' Description: Acquire the previous location :return: the previous location ''' def get_prev_loc(self): return self.prev_loc