コード例 #1
0
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()))
コード例 #2
0
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)


コード例 #3
0
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
コード例 #4
0
ファイル: WeatherAPP.py プロジェクト: irinaignatenok/Dev-Inst
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()
コード例 #5
0
ファイル: Weather.py プロジェクト: FeydCron/RasPyWeb
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
コード例 #6
0
ファイル: weatherHandler.py プロジェクト: Tomjg14/wheater-bot
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