Пример #1
0
    def drawMoon(self,now = None):
        bg = Image.new("RGBA",(self.width,self.height))
        dr = ImageDraw.Draw(bg)
        radius = self.size/5
        sunx1 = self.x + self.size/2 - radius
        sunx2 = self.x + self.size/2 + radius
        suny1 = self.y + self.size/2 - radius
        suny2 = self.y + self.size/2 + radius

        phase = moon.phase(now)
        # print("Moonphase = ",phase)
        el = [sunx1,suny1,sunx2,suny2]
        dr.ellipse(el,fill=(5,5,5),width=0)

        if phase < 7:
            # new moon 0
            pass 
        elif phase < 14:
            # first quarter
            pass
        elif phase < 21:
            # full moon
            pass
        elif phase < 28:
            # last quarter 360 = phase/28 * 360
            pass

        angle = phase/28*360
        start = 180 - angle/2
        end = 180 + angle/2

        dr.pieslice(el,start,end,fill=(80,80,80))

        return bg
Пример #2
0
def render_moonphase(_, query):
    """moonpahse(m)
    A symbol describing the phase of the moon
    """
    moon_phase = moon.phase(date=datetime.datetime.today())
    moon_index = int(int(32.0*moon_phase/28+2)%32/4)
    return MOON_PHASES[moon_index]
Пример #3
0
    def index(self, latitude=None, longitude=None):
        if latitude:
            try:
                latitude = float(latitude)
            except ValueError:
                return 'latitude must be a floating point number'

        if longitude:
            try:
                longitude = float(longitude)
            except ValueError:
                return 'longitude must be a floating point number'

        # Default to Dublin, Ireland
        city = LocationInfo(latitude=(latitude or 53.427),
                            longitude=(longitude or -6.25))
        s = sun(city.observer, datetime.date.today())

        ret = 'Sunrise: %s<br/>\n' % (s['sunrise'].strftime('%H:%M'))
        ret += 'Sunset: %s<br/>\n' % (s['sunset'].strftime('%H:%M'))

        phasenum = moon.phase(datetime.date.today())

        if 14 < phasenum < 15:
            ret += 'Full moon'

        return ret
Пример #4
0
def weather_to_fits(target, verbose=False):
    #Access BOM FTP service for NSW/ACT Forecast
    stat_id = 'IDN60920.xml'  #CANBERRA AIRPORT SUMMARY
    ftp = FTP('ftp2.bom.gov.au')
    ftp.login()
    ftp.cwd('anon/gen/fwo')
    with open(stat_id, 'wb') as fp:
        ftp.retrbinary('RETR ' + stat_id, fp.write)
    ftp.quit()

    #Retrieve forecast for Canberra
    tree = ET.parse(stat_id)
    root = tree.getroot()
    stat_weather = root.findall(
        ".//observations/station/[@stn-name='TIDBINBILLA (PCS)']/period/level/"
    )
    keys = [
        'DELTA_T', 'GUST', 'AIR_TEMP', 'PRESSURE', 'HUMID', 'WIND_DIR',
        'WIND_SPD'
    ]
    choice = [
        'delta_t', 'gust_kmh', 'air_temperature', 'pres', 'rel-humidity',
        'wind_dir_deg', 'wind_spd_kmh'
    ]

    with fits.open(target, mode='update') as hdu:
        target_head = hdu[0].header
        k = 0
        target_head.append(('STATNAME', 'Tidbinbilla (PCS)'))
        for i in range(len(stat_weather)):
            if stat_weather[i].attrib['type'] in choice:
                try:
                    comment = stat_weather[i].attrib['type']\
                        + '  ' + stat_weather[i].attrib['units']
                except KeyError:
                    comment = stat_weather[i].attrib['type']
                try:
                    entry = round(float(stat_weather[i].text), 2)
                except ValueError:
                    entry = stat_weather[i].text
                target_head.append((keys[k], entry, comment))
                k += 1

        phase = round(moon.phase(datetime.date.today()), 2)

        target_head.append(('MOON', phase, 'phase of moon (0-28)'))

        if verbose:
            print(target_head)
Пример #5
0
    async def moon_command(
        self,
        ctx,
    ):
        mon_phase = moon.phase(datetime.datetime.now())
        message = ""
        if mon_phase < 6.99:
            message = "Aktuell ist Neumond :new_moon:"
        elif 6.99 < mon_phase < 13.99:
            message = "Aktuell ist zunehmender Mond :first_quarter_moon:"
        elif 14 < mon_phase < 20.99:
            message = "Aktuell ist Vollmond :full_moon:"
        else:
            message = "Aktuell ist abnehmender Mond :last_quarter_moon:"

        await ctx.send(message)
def moon_phase_name(date, lang='en'):
    '''
    Given a date, this function will return the moon's phase name.
    English by Default
    lang argument:
        'en' = English
        'fr' = French
        'it' = Italian
        'es' = Spanish
        'de' = German
        'no' = Norwegian
        'ru' = Russian
        'cn' = Chinese (Simplified)

        NB: Translations were wupplied by 'Google Translation'.
    '''
    phase_name = {
        'en': ("New Moon", "First Quarter", "Full Moon", "Last Quarter"),
        'fr': ("Nouvelle Lune", "Lune Croissante", "Pleine Lune",
               "Lune Décroissante"),
        'it': ("Nuova Luna", "Luna Crescente", "Luna Piena", "Luna calante"),
        'es': ("Luna nueva", "Luna Creciente", "Luna Llena", "Luna Menguante"),
        'de': ("Neumond", "Halbmond", "Vollmond", "Abnehmender Mond"),
        'no': ("Nymåne", "Halvmåne", "Fullmåne", "Avtagende måne"),
        'ru': ("Новолуние", "полумесяц", "полнолуние", "Убывающая Луна"),
        'cn': ("新月", "新月", "满月", "残月")
    }

    moon_phase = round(moon.phase(date), 2)

    if moon_phase in float_range(0, 7, 0.01):
        return phase_name[lang][0]
    elif moon_phase in float_range(7, 14, 0.01):
        return phase_name[lang][1]
    elif moon_phase in float_range(14, 21, 0.01):
        return phase_name[lang][2]
    elif moon_phase in float_range(21, 28, 0.01):
        return phase_name[lang][3]
    else:
        return None
Пример #7
0
def get_lunar_phase_data(reference_datetime=None, fix_at_noon=True):
    if reference_datetime is None:
        reference_datetime = datetime.datetime.now()

    if fix_at_noon:
        reference_datetime = reference_datetime.replace(hour=12,
                                                        minute=0,
                                                        second=0)

    moon_phase_day = int(phase(date=reference_datetime))

    phase_code = get_lunar_phasecode_from_day(moon_phase_day)
    phase_name = get_lunar_phasename_from_code(phase_code)

    lunar_phase_data = {
        'datetime': reference_datetime,
        'code': phase_code,
        'name': phase_name,
        'moon_phase_day': moon_phase_day
    }

    return lunar_phase_data
Пример #8
0
def drawmoon(clockface):
    """drawmoon - Fill in the moon phase on LEDS 60-75 inclusive

    Args:
        clockface: The Neopixels to draw onto - note that this uses indices 60-75
    """
    moonphase = int(moon.phase())  # 0.0-27.99 - 0 = new moon, 14 = full moon
    gradient = [
        0, 0, 0, 0, 0, 0, 16, 24, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        64, 48, 32, 16, 0, 0, 0, 0, 0
    ]  # Fade gradient - 28 phases
    offset = [0, -2, -4, -5, -6, -5, -4, -2, 0, 2, 4, 5, 6, 5, 4,
              2]  # Phase offset for each of the 16 LEDs in sequence

    for position in range(len(offset)):
        led = position + 60  # LED60=top, then anti-clockwise to LED75
        if moonphase == 0:
            val = 0
        else:
            val = gradient[(moonphase + offset[position]) % len(gradient)]

        clockface[led] = (val // 4, val // 2, val + 4
                          )  # Make it a little but blue
Пример #9
0
    async def async_update(self) -> None:
        """Get the time and updates the states."""
        today = dt_util.now().date()
        state = moon.phase(today)

        if state < 0.5 or state > 27.5:
            self._attr_native_value = STATE_NEW_MOON
        elif state < 6.5:
            self._attr_native_value = STATE_WAXING_CRESCENT
        elif state < 7.5:
            self._attr_native_value = STATE_FIRST_QUARTER
        elif state < 13.5:
            self._attr_native_value = STATE_WAXING_GIBBOUS
        elif state < 14.5:
            self._attr_native_value = STATE_FULL_MOON
        elif state < 20.5:
            self._attr_native_value = STATE_WANING_GIBBOUS
        elif state < 21.5:
            self._attr_native_value = STATE_LAST_QUARTER
        else:
            self._attr_native_value = STATE_WANING_CRESCENT

        self._attr_icon = MOON_ICONS.get(self._attr_native_value)
Пример #10
0
end_date = datetime.date(year2, month2, day2)

#Manual entry
#start_date = datetime.date(2020, 11, 20)
#end_date   = datetime.date(2021, 1, 30)

dates = [
    start_date + datetime.timedelta(n)
    for n in range(int((end_date - start_date).days))
]
#dates

#Get moonphases
moonphases = []
for i in dates:
    moonphases.append(moon.phase(i))

#Plot moonphases

save_option = input('Do you want to save the plot? input: y or n :')
if save_option == 'y':

    plt.figure(figsize=(15, 8))
    ax = plt.gca()
    plt.plot(dates, moonphases, linewidth=2.5, color='b', label='Moonphases')
    ax.axhline(y=6.99, color='g', linestyle='--', linewidth=2, alpha=0.9)
    ax.axhline(y=14, color='r', linestyle='--', linewidth=2, alpha=0.9)
    ax.axhline(y=20.99, color='r', linestyle='--', linewidth=2, alpha=0.9)
    ax.axhline(y=27.99, color='b', linestyle='--', alpha=0.9)

    #fills
Пример #11
0
from datetime import date, timedelta
from astral import moon
now = date.today()
for i in range(30):
    day = now + timedelta(days=i)
    moon_phase = moon.phase(day)
    print(day.isoformat() + ' Moon Phase: %d' % moon_phase)
Пример #12
0
def render_moonday(_, query):
    """moonday(M)
    An number describing the phase of the moon (days after the New Moon)
    """
    moon_phase = moon.phase(date=datetime.datetime.today())
    return str(int(moon_phase))
Пример #13
0
def test_moon_phase(date_, phase):
    """Test moon phase calculation"""
    assert moon.phase(date_) == pytest.approx(phase, abs=0.01)
Пример #14
0
def draw_astronomical(city_name, geo_data, config):
    datetime_day_start = datetime.datetime.now().replace(hour=0,
                                                         minute=0,
                                                         second=0,
                                                         microsecond=0)

    city = LocationInfo()
    city.latitude = geo_data["latitude"]
    city.longitude = geo_data["longitude"]
    city.timezone = geo_data["timezone"]

    answer = ""
    moon_line = ""
    for time_interval in range(72):

        current_date = (datetime_day_start +
                        datetime.timedelta(hours=1 * time_interval)).replace(
                            tzinfo=pytz.timezone(geo_data["timezone"]))

        try:
            dawn = sun.dawn(city.observer, date=current_date)
        except ValueError:
            dawn = current_date

        try:
            dusk = sun.dusk(city.observer, date=current_date)
        except ValueError:
            dusk = current_date + datetime.timedelta(hours=24)

        try:
            sunrise = sun.sunrise(city.observer, date=current_date)
        except ValueError:
            sunrise = current_date

        try:
            sunset = sun.sunset(city.observer, date=current_date)
        except ValueError:
            sunset = current_date + datetime.timedelta(hours=24)

        char = "."
        if current_date < dawn:
            char = " "
        elif current_date > dusk:
            char = " "
        elif dawn <= current_date and current_date <= sunrise:
            char = u"─"
        elif sunset <= current_date and current_date <= dusk:
            char = u"─"
        elif sunrise <= current_date and current_date <= sunset:
            char = u"━"

        answer += char

        if config.get("view") in ["v2n", "v2d"]:
            moon_phases = constants.MOON_PHASES_WI
            moon_phases = [" %s" % x for x in moon_phases]
        else:
            moon_phases = constants.MOON_PHASES

        # moon
        if time_interval in [0, 23, 47, 69]:  # time_interval % 3 == 0:
            moon_phase = moon.phase(date=datetime_day_start +
                                    datetime.timedelta(hours=time_interval))
            moon_phase_emoji = moon_phases[int(
                math.floor(moon_phase * 1.0 / 28.0 * 8 + 0.5)) %
                                           len(moon_phases)]
            #    if time_interval in [0, 24, 48, 69]:
            moon_line += moon_phase_emoji  # + " "
        elif time_interval % 3 == 0:
            if time_interval not in [24, 28]:  #se:
                moon_line += "   "
            else:
                moon_line += " "

    answer = moon_line + "\n" + answer + "\n"
    answer += "\n"
    return answer
Пример #15
0
    def run(self):
        global stats

        temp_upd = None
        if plugin_options['use_footer']:
            temp_upd = showInFooter() #  instantiate class to enable data in footer
            temp_upd.button = "sunrise_and_sunset/status"    # button redirect on footer
            temp_upd.label =  _('Sunrise and Sunset')       # label on footer
            msg = _('Waiting to state')
            temp_upd.val = msg.encode('utf8').decode('utf8') # value on footer

        try:
            from astral.geocoder import database
        except ImportError:
            log.clear(NAME)
            log.info(NAME, _('Astral is not installed.'))
            log.info(NAME, _('Please wait installing astral...'))
            cmd = "pip3 install astral"
            run_command(cmd)
            log.info(NAME, _('Astral is now installed.'))        

        while not self._stop_event.is_set():
            try:
                if plugin_options['use_astro']:
                    log.clear(NAME)
                    city = None
                    found_name = ''
                    found_region = ''
                    found_timezone =''
                    found_latitude = 0
                    found_longitude = 0
                    try:
                        if plugin_options['location'] != 0:     # 0 is none location
                            from astral.geocoder import database, lookup
                            find_loc = city_table[plugin_options['location']]
                            city = lookup(find_loc, database()) # return example: LocationInfo(name='Addis Ababa', region='Ethiopia', timezone='Africa/Addis_Ababa', latitude=9.033333333333333, longitude=38.7)
                            found_name = city.name
                            found_region = city.region
                            found_timezone = city.timezone
                            found_latitude = city.latitude
                            found_longitude = city.longitude
                        else:
                            if plugin_options['custom_location'] and plugin_options['custom_region'] and plugin_options['custom_timezone'] and plugin_options['custom_lati_longit']:
                                from astral.geocoder import add_locations, database, lookup
                                db = database()
                                _loc = '{},{},{},{}'.format(plugin_options['custom_location'], plugin_options['custom_region'], plugin_options['custom_timezone'], plugin_options['custom_lati_longit'])
                                add_locations(_loc, db) # "Somewhere,Secret Location,UTC,24°28'N,39°36'E"
                                city = lookup(plugin_options['custom_location'], db)
                                found_name = city.name
                                found_region = city.region
                                found_timezone = city.timezone
                                found_latitude = city.latitude
                                found_longitude = city.longitude
                            else:
                                log.info(NAME, _('You must fill in all required fields (location, region, timezone/name, latitude and longitude!'))
                                city = None

                        s = None 
                        if city is not None:
                            log.info(NAME, _('Found city'))
                            log.info(NAME, _('Name') + ': {}'.format(found_name))
                            log.info(NAME, _('Region') + ': {}'.format(found_region))
                            log.info(NAME, _('Timezone') + ': {}'.format(found_timezone))
                            log.info(NAME, _('Latitude') + ': {}'.format(round(found_latitude, 2)))
                            log.info(NAME, _('Longitude') + ': {}'.format(round(found_longitude, 2)))

                            import datetime
                            from astral.sun import sun

                            today =  datetime.date.today()

                            _day = int(today.strftime("%d"))
                            _month = int(today.strftime("%m"))
                            _year = int(today.strftime("%Y"))

                            s = sun(city.observer, date=datetime.date(_year, _month, _day), tzinfo=found_timezone)
                            log.info(NAME, '_______________ ' + '{}'.format(today) + ' _______________')
                            log.info(NAME, _('Dawn') + ': {}'.format(s["dawn"].strftime("%H:%M:%S")))
                            log.info(NAME, _('Sunrise') + ': {}'.format(s["sunrise"].strftime("%H:%M:%S")))
                            log.info(NAME, _('Noon') + ': {}'.format(s["noon"].strftime("%H:%M:%S")))
                            log.info(NAME, _('Sunset') + ': {}'.format(s["sunset"].strftime("%H:%M:%S")))
                            log.info(NAME, _('Dusk') + ': {}'.format(s["dusk"].strftime("%H:%M:%S")))

                            msg = _('Sunrise') + ': {}, '.format(s["sunrise"].strftime("%H:%M:%S")) + _('Sunset') + ': {}'.format(s["sunset"].strftime("%H:%M:%S"))

                            from astral import moon
                            m = moon.phase(datetime.date(_year, _month, _day))
                            log.info(NAME, _('Moon phase') + ': {}'.format(round(m, 2)))
                            msg += ', ' +  _('Moon phase') + ': '
                            if m < 7:
                                log.info(NAME, '* ' + _('New moon'))
                                msg += _('New moon')
                            elif m >= 7  and m < 14:
                                log.info(NAME, '* ' + _('First quarter'))
                                msg += _('First quarter')
                            elif m >= 14  and m < 21:
                                log.info(NAME, '* ' + _('Full moon'))
                                msg += _('Full moon')
                            elif m >= 21  and m < 28:
                                log.info(NAME, '* ' + _('Last quarter'))
                                msg += _('Last quarter')
                            else:
                                log.info(NAME, '* ' + _('Unkown phase'))
                                msg += _('Unkown phase')

                    except Exception:
                        self.started.set()
                        log.error(NAME, _('Astro plug-in') + ':\n' + traceback.format_exc())
                        self._sleep(2)
                else:
                    msg =_(u'Plugin is not enabled')

                if plugin_options['use_footer']:
                    if temp_upd is not None:
                        temp_upd.val = msg.encode('utf8').decode('utf8')  # value on footer
                    else:
                        log.error(NAME, _('Error: restart this plugin! Show in homepage footer have enabled.'))

                self._sleep(3600)

            except Exception:
                self.started.set()
                log.error(NAME, _('Astro plug-in') + ':\n' + traceback.format_exc())
                self._sleep(60)
Пример #16
0
def get(latitude, longitude, useragent_string, flask_app=None):
	'''
	Use the weather data from the NOAA Weather API.
	
	Latitude
	longitude: geolocation obtained from the request URL
	useragent_string: required by NOAA to identify the caller.  See 
	                  https://www.weather.gov/documentation/services-web-api
	flask_app : an object containing a Flask application's details.  Used
                to allow us to write into the application log.
	                   
	Returns a DarkSky JSON structure that can be the output of this web
	service	
	'''
	
	#  Get the NOAA grid coordinates, timezone and URL links for this 
	#  location from their "points" service, based on the lat/long
	noaa_headers = {
		'User-Agent': useragent_string,
		'Accept': 'application/geo+json'
	}
	url = 'https://api.weather.gov/points/{},{}'.format(latitude, longitude)
	noaa_points_obj = functions.getURL(url, noaa_headers, flask_app)
	if noaa_points_obj is False:
		flask_app.logger.critical('NOAA request for location information on this latitude and longitude failed: {},{}'.format(latitude, longitude))
		return False

	#  Create the output JSON structure using the location information
	#  that came back from the service
	output = {
		'latitude': latitude,
		'longitude': longitude,
		'timezone': functions.getKeyValue(noaa_points_obj, ['properties', 'timeZone']),
		'currently': {},
		#  NOAA does not provide minutely data
		'minutely': {},
		'hourly': {},
		'daily': {},
		'alerts': [],
		'flags': {
			'sources': [],
			'units': 'us'
		}
	}

	#  Define a location for the astral functions that determine sunrise
	#  and sunset for the "daily" section of the output
	astral_location = LocationInfo('dummy_name', 'dummy_region', functions.getKeyValue(noaa_points_obj, ['properties', 'timeZone']), latitude, longitude)
	
	#  Set the system timezone so that all times are local relative to
	#  this lat/long
	os.environ['TZ'] = output['timezone']
	
	#  Calculate the timezone's offset from UTC in hours and add that to the
	#  output
	tz_now = datetime.datetime.now(pytz.timezone(output['timezone']))
	output['offset'] = tz_now.utcoffset().total_seconds() / 3600

	#  Using the stations URL that we got from the NOAA points lookup, find
	#  the nearest station and get its dstance away.  Add this to the output.
	url = functions.getKeyValue(noaa_points_obj, ['properties', 'observationStations']);
	noaa_stations_obj = functions.getURL(url, noaa_headers, flask_app)
	if noaa_stations_obj is False:
		flask.abort(501)
	for feature in functions.getKeyValue(noaa_stations_obj,['features']):
		miles = great_circle((latitude, longitude), (functions.getKeyValue(feature, ['geometry', 'coordinates'])[1], functions.getKeyValue(feature, ['geometry', 'coordinates'])[0])).miles
		if 'nearest-station' not in output['flags'] or miles < output['flags']['nearest-station']:
			noaa_station_url = functions.getKeyValue(feature, ['id'])
			output['flags']['nearest-station'] = round(miles, 2)

	#  Do all of the rest of the NOAA API calls simultaneously, in
	#  seperate threads, to save time
	with concurrent.futures.ThreadPoolExecutor() as executor:
		#  Get the current conditions
		url = '{}/observations/latest'.format(noaa_station_url)
		get_current = executor.submit(functions.getURL, url, noaa_headers, flask_app)

		url = functions.getKeyValue(noaa_points_obj, ['properties', 'forecastHourly']);
		get_hourly = executor.submit(functions.getURL, url, noaa_headers, flask_app)

		#  Get the grid forecast data
		url = functions.getKeyValue(noaa_points_obj, ['properties', 'forecastGridData']);
		get_griddata = executor.submit(functions.getURL, url, noaa_headers, flask_app)

		#  Get the daily forecast data
		url = functions.getKeyValue(noaa_points_obj, ['properties', 'forecast']);
		get_daily = executor.submit(functions.getURL, url, noaa_headers, flask_app)
		
		#  Get the alerts
		url = 'https://api.weather.gov/alerts?point={},{}'.format(latitude, longitude)
		get_alerts = executor.submit(functions.getURL, url, noaa_headers, flask_app)
		
		#  Get the list of all the counties in this location's state
		#  and their id codes.
		url = 'https://api.weather.gov/zones?type=county&area={}'.format(functions.getKeyValue(noaa_points_obj, ['properties', 'relativeLocation', 'properties', 'state']))
		get_counties = executor.submit(functions.getURL, url, noaa_headers, flask_app)

		#  Get the list of forecast zones in this location's state
		#  and their id codes
		url = 'https://api.weather.gov/zones?type=forecast&area={}'.format(functions.getKeyValue(noaa_points_obj, ['properties', 'relativeLocation', 'properties', 'state']))
		get_zones = executor.submit(functions.getURL, url, noaa_headers, flask_app)

		try:
			noaa_current_obj = get_current.result()
		except:
			print('Exception occurred during noaa_current_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_current_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_current_obj = None
		#  If this request failed, return an empty dictionary
		if not noaa_current_obj:
			return False

		try:
			noaa_hourly_obj = get_hourly.result()
		except:
			print('Exception occurred during noaa_hourly_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_hourly_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_hourly_obj = None
		#  If this request failed, return an empty dictionary
		if not noaa_hourly_obj:
			return False

		try:
			noaa_griddata_obj = get_griddata.result()
		except:
			print('Exception occurred during noaa_griddata_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_griddata_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_griddata_obj = None
		#  If this request failed, return an empty dictionary
		if not noaa_griddata_obj:
			return False
			
		try:
			noaa_daily_obj = get_daily.result()
		except:
			print('Exception occurred during noaa_daily_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_daily_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_daily_obj = None
		#  If this request failed, return an empty dictionary
		if not noaa_daily_obj:
			return False

		try:
			noaa_alerts_obj = get_alerts.result()
		except:
			print('Exception occurred during noaa_alerts_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_alerts_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_alerts_obj = None

		try:
			noaa_counties_obj = get_counties.result()
		except:
			print('Exception occurred during noaa_counties_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_counties_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_counties_obj = None

		try:
			noaa_zones_obj = get_zones.result()
		except:
			print('Exception occurred during noaa_counties_obj API call: {}'.format(sys.exc_info()))
			if flask_app:
				flask_app.logger.error('Exception occurred during noaa_counties_obj API call: {}'.format(sys.exc_info()[0]))
			noaa_zones_obj = None

	#  Put the county codes and their associated names into a dictionary.
	noaa_county_list = {};
	if noaa_counties_obj:
		for feature in functions.getKeyValue(noaa_counties_obj, ['features']):
			noaa_county_list[functions.getKeyValue(feature, ['properties', 'id'])] = functions.getKeyValue(feature, ['properties', 'name']);

	#  Append the list of forecast zones to the county list dictionary.
	#  Sometimes they use these in alerts instead of county codes.
	if noaa_zones_obj:
		for feature in functions.getKeyValue(noaa_zones_obj, ['features']):
			noaa_county_list[functions.getKeyValue(feature, ['properties', 'id'])] = functions.getKeyValue(feature, ['properties', 'name']);

			
	#--------------------------   C u r r e n t l y   --------------------------#

	#  Populate the output dictionary with the current observations from
	#  that station we just found
	props = functions.getKeyValue(noaa_current_obj, ['properties'])
	if props:
		output['currently'] = {
			'time': functions.getKeyValue(props, ['timestamp'], lambda x: int(functions.parseInterval(x)['start'])),
			'summary': functions.getKeyValue(props, ['textDescription'], lambda x: x.capitalize()),
			'icon': functions.getKeyValue(props, ['icon'], lambda x: _mapIcons(x, flask_app)),
			#'nearestStormDistance': None,
			'precipIntensity': functions.getKeyValue(props, ['precipitationLastHour', 'value'], lambda x: round(x / 39.37014, 2)),
			#'precipIntensityError': None,
			#'precipProbability': None,
			#'precipType': None,
			'temperature': functions.getKeyValue(props, ['temperature', 'value'], lambda x: round((x * 9 / 5) + 32, 2)),
			'apparentTemperature': functions.getKeyValue(props, ['windchill', 'value'], lambda x: round((x * 9 / 5) + 32, 2)) if functions.getKeyValue(props, ['windchill', 'value']) else functions.getKeyValue(props, ['heatIndex', 'value'], lambda x: round((x * 9 / 5) + 32, 2)),
			'dewPoint': functions.getKeyValue(props, ['dewpoint', 'value'], lambda x: round((x * 9 / 5) + 32, 2)),
			'humidity': round(100 - (5 * (props['temperature']['value'] - props['dewpoint']['value'])), 2) if functions.getKeyValue(props, ['temperature', 'value']) and functions.getKeyValue(props, ['dewpoint', 'value']) else None,
			'pressure': functions.getKeyValue(props, ['barometricpressure', 'value'], lambda x: round(x / 100, 2)),
			'windSpeed': functions.getKeyValue(props, ['windSpeed', 'value'], lambda x: round(x * 0.621371, 2)),
			'windGust': functions.getKeyValue(props, ['windGust', 'value'], lambda x: round(x * 0.621371, 2)),
			'windBearing': functions.getKeyValue(props, ['windDirection', 'value']),
			#'cloudCover': None,
			#'uvIndex': None,
			'visibility': functions.getKeyValue(props, ['visibility', 'value'], lambda x: round(x / 1609.34, 2)),
			#'ozone': None
		}

	#-----------------------------   H o u r l y   -----------------------------#
	
	#  Populate the output dictionary with the hourly data
	hours = functions.getKeyValue(noaa_hourly_obj, ['properties', 'periods']);
	if hours:
		hourly_data = []
		for hour in hours:
			#  Break out of the loop once we've got 48 hours worth
			if len(hourly_data) >= 48:
				break
			#  Include this period if its end time is greater than
			#  the current time
			if functions.parseInterval(hour['endTime'])['start'] > datetime.datetime.now().timestamp():
				hourly_data.append({
					'time': functions.parseInterval(hour['startTime'])['start'],
					'summary': functions.getKeyValue(hour, ['shortForecast'], lambda x: x.capitalize()),
					'icon': functions.getKeyValue(hour, ['icon'], lambda x: _mapIcons(x, flask_app)),
					#'pressure': None,
					#'uvIndex': None,
					#'ozone': None
				})

		#  Use NOAA's grid forecast to complete the hourly data array
		quantities = functions.getKeyValue(noaa_griddata_obj, ['properties', 'quantitativePrecipitation', 'values']);
		if quantities:
			for quantity in quantities:
				interval = functions.parseInterval(quantity['validTime'])
				hours = (interval['end'] - interval['start']) / 3600
				perhour = round(quantity['value'] / 25.4 / hours, 2)
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['precipIntensity'] = perhour
					if hourly_data[i]['time'] > interval['end']:
						break

		snowamounts = functions.getKeyValue(noaa_griddata_obj, ['properties', 'snowfallAmount', 'values']);
		if snowamounts:
			for snow in snowamounts:
				interval = functions.parseInterval(snow['validTime'])
				hours = (interval['end'] - interval['start']) / 3600
				perhour = round(snow['value'] / 25.4 / hours, 2)
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						if 'precipIntensity' in hourly_data[i]:
							if perhour > hourly_data[i]['precipIntensity']:
								hourly_data[i]['precipIntensity'] = perhour
						else:
							hourly_data[i]['precipIntensity'] = perhour
					if hourly_data[i]['time'] > interval['end']:
						break

		probabilities = functions.getKeyValue(noaa_griddata_obj, ['properties', 'probabilityOfPrecipitation', 'values']);
		if probabilities:
			for probability in probabilities:
				interval = functions.parseInterval(probability['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['precipProbability'] = round(probability['value'] / 100, 2)
					if hourly_data[i]['time'] > interval['end']:
						break

						
		temperatures = functions.getKeyValue(noaa_griddata_obj, ['properties', 'temperature', 'values']);
		if temperatures:
			for temp in temperatures:
				interval = functions.parseInterval(temp['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['temperature'] = round((temp['value'] * 9 / 5) + 32, 2)
					if hourly_data[i]['time'] > interval['end']:
						break
						
		apparents = functions.getKeyValue(noaa_griddata_obj, ['properties', 'apparentTemperature', 'values']);
		if apparents:
			for apparent in apparents:
				interval = functions.parseInterval(apparent['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['apparentTemperature'] = round((apparent['value'] * 9 / 5) + 32, 2)
					if hourly_data[i]['time'] > interval['end']:
						break

		dewpoints = functions.getKeyValue(noaa_griddata_obj, ['properties', 'dewpoint', 'values']);
		if dewpoints:
			for dewpoint in dewpoints:
				interval = functions.parseInterval(dewpoint['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['dewpoint'] = round((dewpoint['value'] * 9 / 5) + 32, 2)
					if hourly_data[i]['time'] > interval['end']:
						break
						
		humidities = functions.getKeyValue(noaa_griddata_obj, ['properties', 'relativeHumidity', 'values']);
		if humidities:
			for humidity in humidities:
				interval = functions.parseInterval(humidity['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['humdity'] = round(humidity['value'] / 100, 2)
					if hourly_data[i]['time'] > interval['end']:
						break
						
		windspeeds = functions.getKeyValue(noaa_griddata_obj, ['properties', 'windSpeed', 'values']);
		if windspeeds:
			for speed in windspeeds:
				interval = functions.parseInterval(speed['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['windSpeed'] = round(speed['value'] * 0.621371, 2)
					if hourly_data[i]['time'] > interval['end']:
						break

		windgusts = functions.getKeyValue(noaa_griddata_obj, ['properties', 'windGust', 'values']);
		if windgusts:
			for gust in windgusts:
				interval = functions.parseInterval(gust['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['windGust'] = round(gust['value'] * 0.621371, 2)
					if hourly_data[i]['time'] > interval['end']:
						break

		winddirections = functions.getKeyValue(noaa_griddata_obj, ['properties', 'windDirection', 'values']);
		if winddirections:
			for direction in winddirections:
				interval = functions.parseInterval(direction['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['windBearing'] = round(direction['value'])
					if hourly_data[i]['time'] > interval['end']:
						break

		skycovers = functions.getKeyValue(noaa_griddata_obj, ['properties', 'skyCover', 'values']);
		if skycovers:
			for skycover in skycovers:
				interval = functions.parseInterval(skycover['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['cloudCover'] = round(skycover['value'] / 100, 2)
					if hourly_data[i]['time'] > interval['end']:
						break


		visibilities = functions.getKeyValue(noaa_griddata_obj, ['properties', 'visibility', 'values']);
		if visibilities:
			for visibility in visibilities:
				interval = functions.parseInterval(visibility['validTime'])
				for i in range(len(hourly_data)):
					if hourly_data[i]['time'] >= interval['start'] and hourly_data[i]['time'] < interval['end']:
						hourly_data[i]['visibility'] = round(visibility['value'] / 1609.34, 2)
					if hourly_data[i]['time'] > interval['end']:
						break

		#  Add the hourly data array to the output dictionary
		if len(hourly_data) > 0:
			output['hourly'] = {
				'summary': hourly_data[0]['summary'],
				'icon': hourly_data[0]['icon'],
				'data': hourly_data
			}
			
	#------------------------------   D a i l y   ------------------------------#
	
	#  Populate the output dictionary with the hourly data.  NOAA
	#  provides seperate daytime and nighttime forecasts for each day,
	#  we focus on the daytime forecasts
	daily_data = []
	periods = functions.getKeyValue(noaa_daily_obj, ['properties', 'periods'])
	
	#  Calculate UNIX Epoch timestamp for the first day in the daily
	#  forecast array
	d = datetime.datetime.now()
	d = datetime.datetime.combine(datetime.date(d.year, d.month, d.day), datetime.time())
	d = pytz.timezone(functions.getKeyValue(noaa_points_obj, ['properties', 'timeZone'])).localize(d)
	timestamp = int(d.timestamp())
	
	#  Build an array to hold the daily forecasts
	for i in range(len(periods)):
		if _dailyEpochTime(periods[i]['startTime']) == timestamp:
			the_sun = sun(astral_location.observer, date=datetime.datetime.utcfromtimestamp(timestamp))
			daily_data.append({
				'time': timestamp,
				'summary': functions.getKeyValue(periods, [i, 'shortForecast']),
				'icon': functions.getKeyValue(periods, [i, 'icon'], lambda x: _mapIcons(x, flask_app)),
				'sunriseTime': round(the_sun['sunrise'].timestamp()),
				'sunsetTime': round(the_sun['sunset'].timestamp()),
				'moonPhase': round(moon.phase(datetime.datetime.utcfromtimestamp(timestamp)) / 27.99, 2),
				#'precipIntensity', None,
				#'precipIntensityMax',
				#'precipIntensityMaxTiome',
				'precipProbability': None,
				#'precipType': None,
				'temperatureHigh': None,
				'temperatureHighTime': None,
				'temperatureLow': None,
				'temperatureLowTime': None,
				'apparentTemperatureHigh': None,
				'apparentTemperatureHighTime': None,
				'apparentTemperatureLow': None,
				'apparentTemperatureLowTime': None,
				'dewPoint': None,
				'humidity': None,
				#'pressure': None,
				'windSpeed': None,
				'windGust': None,
				'windGustTime': None,
				'windBearing': None,
				'cloudCover': None,
				#'uvIndex': None,
				#'uvIndexTime', None,
				'visibility': None,
				#'ozone': None,
				'temperatureMin': None,
				'temperatureMinTime': None,
				'temperatureMax': None,
				'temperatureMaxTime': None,
				'apparentTemperatureMin': None,
				'apparentTemperatureMinTime': None,
				'apparentTemperatureMax': None,
				'apparentTemperatureMaxTime': None
			})
			timestamp = timestamp + (3600 * 24)
			
	#  Fill in remaining daily data using the NOAA gridpoint forecast query
	props = functions.getKeyValue(noaa_griddata_obj, ['properties'])
	for i in range(len(daily_data)):
		start = daily_data[i]['time']
		end = start + (3600 * 24)

		#  Scan through each day's temperature data and get the highs and lows
		for value in props['temperature']['values']:
			timestamp = functions.getKeyValue(value, ['validTime'], lambda x: functions.parseInterval(x)['start'])
			if timestamp >= end:
				break;
			temp = functions.getKeyValue(value, ['value']);
			if temp != None:
				temp = round((temp * 9 / 5) + 32, 2)
				if timestamp >= start and timestamp < end:
					if not daily_data[i]['temperatureHigh'] or temp > daily_data[i]['temperatureHigh']:
						daily_data[i]['temperatureHigh'] = temp
						daily_data[i]['temperatureHighTime'] = timestamp
						daily_data[i]['temperatureMax'] = temp
						daily_data[i]['temperatureMaxTime'] = timestamp
					if not daily_data[i]['temperatureLow'] or temp < daily_data[i]['temperatureLow']:
						daily_data[i]['temperatureLow'] = temp
						daily_data[i]['temperatureLowTime'] = timestamp
						daily_data[i]['temperatureMin'] = temp
						daily_data[i]['temperatureMinTime'] = timestamp
		for value in props['apparentTemperature']['values']:
			timestamp = functions.getKeyValue(value, ['validTime'], lambda x: functions.parseInterval(x)['start'])
			if timestamp >= end:
				break;
			temp = functions.getKeyValue(value, ['value']);
			if temp != None:
				temp = round((temp * 9 / 5) + 32, 2)
				if timestamp >= start and timestamp < end:
					if not daily_data[i]['apparentTemperatureHigh'] or temp > daily_data[i]['apparentTemperatureHigh']:
						daily_data[i]['apparentTemperatureHigh'] = temp
						daily_data[i]['apparentTemperatureHighTime'] = timestamp
						daily_data[i]['apparentTemperatureMax'] = temp
						daily_data[i]['apparentTemperatureMaxTime'] = timestamp
					if not daily_data[i]['apparentTemperatureLow'] or temp < daily_data[i]['apparentTemperatureLow']:
						daily_data[i]['apparentTemperatureLow'] = temp
						daily_data[i]['apparentTemperatureLowTime'] = timestamp
						daily_data[i]['apparentTemperatureMin'] = temp
						daily_data[i]['apparentTemperatureMinTime'] = timestamp
		
		#  Calculate the average dewpoint temperature for the day
		total = 0;
		total_hours = 0;
		for value in props['dewpoint']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				dp = functions.getKeyValue(value, ['value'])
				if dp != None:
					total = total + (dp * hours);
					total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['dewPoint'] = round((total / total_hours * 9 / 5) + 32, 2);

		#  Calculate the average humidity for the day
		total = 0;
		total_hours = 0;
		for value in props['relativeHumidity']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				hum = functions.getKeyValue(value, ['value'])
				if hum != None:
					total = total + (hum * hours);
					total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['humidity'] = round(total / total_hours / 100, 2);

		#  Calculate the average cloudCover percentage for the day
		total = 0;
		total_hours = 0;
		for value in props['skyCover']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				clo = functions.getKeyValue(value, ['value'])
				if clo != None:
					total = total + (clo * hours);
					total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['cloudCover'] = round(total / total_hours / 100, 2);

		#  Calculate the average windDirection for the day
		total = 0;
		total_hours = 0;
		for value in props['windDirection']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				dir = functions.getKeyValue(value, ['value'])
				if dir != None:
					total = total + (dir * hours);
					total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['windBearing'] = round(total / total_hours);

		#  Calculate the average windSpeed for the day
		total = 0;
		total_hours = 0;
		for value in props['windSpeed']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				spe = functions.getKeyValue(value, ['value'])
				if spe != None:
					total = total + (spe * hours);
					total_hours = total_hours + hours;
				total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['windSpeed'] = round(total / total_hours * 0.621371, 2);

		#  Calculate the average precipitation probability for the day
		total = 0;
		total_hours = 0;
		for value in props['probabilityOfPrecipitation']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				pro = functions.getKeyValue(value, ['value'])
				if pro != None:
					total = total + (pro * hours);
					total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['precipProbability'] = round(total / total_hours / 100, 2);

		#  Calculate the average visibility for the day (remember that
		#  NOAA only provides this data for the first 24 hours (2 days.)
		total = 0;
		total_hours = 0;
		for value in props['visibility']['values']:
			interval = functions.parseInterval(functions.getKeyValue(value, ['validTime']))
			if interval['end'] > start and interval['start'] <= end:
				if interval['start'] < start:
					interval['start'] = start
				if interval['end'] > end:
					interval['end'] = end
				hours = (interval['end'] - interval['start']) / 3600;
				vis = functions.getKeyValue(value, ['value'])
				if vis != None:
					total = total + (vis * hours);
					total_hours = total_hours + hours;
		if total_hours > 0:
			daily_data[i]['visibility'] = round(total / total_hours / 1609.34, 2);

		#  Get the maximum windGust for the day and its associated timestamp
		for prop in props['windGust']['values']:
			timestamp = functions.getKeyValue(prop, ['validTime'], lambda x: functions.parseInterval(x)['start']);
			if timestamp >= end:
				break
			value = functions.getKeyValue(prop, ['value'])
			if value != None:
				value = round(value * 0.621371, 2)
				if timestamp >= start and timestamp < end:
					if not daily_data[i]['windGust'] or value > daily_data[i]['windGust']:
						daily_data[i]['windGust'] = value
						daily_data[i]['windGustTime'] = timestamp
				
	#  Add the daily data array to the output dictionary
	if len(daily_data) > 0:
		output['daily'] = {
			'summary': daily_data[0]['summary'],
			'icon': daily_data[0]['icon'],
			'data': daily_data
		}
				
	#-----------------------------   A l e r t s   -----------------------------#

	#  Popluate the output dictionary with any alerts that pertain to
	#  this location.
	if noaa_alerts_obj:
		alerts = functions.getKeyValue(noaa_alerts_obj, ['features'])
		if alerts:
			alert_data = []
			for alert in alerts:
				props = functions.getKeyValue(alert, ['properties'])
				#  Don't include expired alerts
				if functions.getKeyValue(props, ['expires'], lambda x: functions.parseInterval(x)['start']) > datetime.datetime.now().timestamp():
					#  Use the noaa_county_list dictionary we built at the
					#  beginning to convert the county IDs listed in the
					#  alert to county names.
					regions = []
					for county_id in functions.getKeyValue(props, ['geocode', 'UGC']):
						regions.append(noaa_county_list[county_id])
					#  Populate the alert data array with the data from NOAA	
					alert_data.append({
						'title': functions.getKeyValue(props, ['event']),
						'regions': regions,
						'severity': functions.getKeyValue(props, ['severity']),
						'time': functions.getKeyValue(props, ['onset'],  lambda x: functions.parseInterval(x)['start']),
						'expires': functions.getKeyValue(props, ['expires'],  lambda x: functions.parseInterval(x)['start']),
						'description': functions.getKeyValue(props, ['description'], lambda x: re.sub(r'\s+', ' ', x)),
						'url': functions.getKeyValue(props,['@id'])
					})
			
			#  Add the alerts data array to the output dictionary	
			output['alerts'] = alert_data
	
	#  Flag the output as including data from NOAA	
	output['flags']['sources'] = 'noaa',

	return output
Пример #17
0
def get(latitude, longitude, apikey, input_dictionary=None, flask_app=None):
    '''
	Use the weather data from the Climacell API.  This data will overwrite
	and extend what we got from NOAA.
	
	Latitude
	longitude: geolocation obtained from the request URL
	apikey: the user's Climacell API key from a free account (or paid)
	input_dictionary: a DarkSky JSON structure created by another routine
	                  in this script like the getNOAAWeatherInfo rountine,
	                  for example.  This is optional.  If a JSON structure
	                  isn't passed through, then one will be created from
	                  scratch.
	flask_app : an object containing a Flask application's details.  Used
                to allow us to write into the application log.
	                   
	Returns a DarkSky JSON structure that can be the output of this web
	service
	'''

    cc_headers = {'Accept': 'application/json', 'apikey': apikey}

    #  Do all of the Climacell API calls simultaneously, in seperate
    #  threads, to save time
    with concurrent.futures.ThreadPoolExecutor() as executor:
        url = 'https://api.climacell.co/v3/weather/realtime?lat={}&lon={}&unit_system=us&fields=precipitation,precipitation%3Ain%2Fhr,precipitation_type,temp,feels_like,dewpoint,wind_speed,wind_gust,baro_pressure%3AhPa,visibility,humidity,wind_direction,cloud_cover,weather_code,o3'.format(
            latitude, longitude)
        get_current = executor.submit(functions.getURL, url, cc_headers,
                                      flask_app)

        minutely_starttime = (
            datetime.datetime.utcnow() +
            datetime.timedelta(minutes=1)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
        minutely_endtime = (
            datetime.datetime.utcnow() +
            datetime.timedelta(minutes=61)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
        url = 'https://api.climacell.co/v3/weather/nowcast?lat={}&lon={}&unit_system=us&fields=precipitation%3Ain%2Fhr,precipitation_type&start_time={}&end_time={}&timestep=1'.format(
            latitude, longitude, minutely_starttime, minutely_endtime)
        get_minutely = executor.submit(functions.getURL, url, cc_headers,
                                       flask_app)

        url = 'https://api.climacell.co/v3/weather/forecast/hourly?lat={}&lon={}&unit_system=us&fields=precipitation,precipitation%3Ain%2Fhr,precipitation_type,precipitation_probability,temp,feels_like,dewpoint,wind_speed,wind_gust,baro_pressure%3AhPa,visibility,humidity,wind_direction,cloud_cover,weather_code,o3&start_time=now'.format(
            latitude, longitude)
        get_hourly = executor.submit(functions.getURL, url, cc_headers,
                                     flask_app)

        url = 'https://api.climacell.co/v3/weather/forecast/daily?lat={}&lon={}&start_time=now&unit_system=us&fields=temp,feels_like,wind_speed,wind_direction,baro_pressure%3AhPa,precipitation,precipitation%3Ain%2Fhr,precipitation_probability,visibility,humidity,sunrise,sunset,weather_code'.format(
            latitude, longitude)
        get_daily = executor.submit(functions.getURL, url, cc_headers,
                                    flask_app)

        try:
            cc_current_obj = get_current.result()
        except:
            print(
                'Exception occurred during cc_current_obj API call: {}'.format(
                    sys.exc_info()))
            if flask_app:
                flask_app.logger.error(
                    'Exception occurred during cc_current_obj API call: {}'.
                    format(sys.exc_info()[0]))
            cc_current_obj = None
        #  If this request failed, return an empty dictionary
        if not cc_current_obj:
            if input_dictionary:
                return input_dictionary
            else:
                return False

        try:
            cc_minutely_obj = get_minutely.result()
        except:
            print('Exception occurred during cc_minutely_obj API call: {}'.
                  format(sys.exc_info()))
            if flask_app:
                flask_app.logger.error(
                    'Exception occurred during cc_minutely_obj API call: {}'.
                    format(sys.exc_info()[0]))
            cc_minutely_obj = None
        #  If this request failed, return an empty dictionary
        if not cc_minutely_obj:
            if input_dictionary:
                return input_dictionary
            else:
                return False

        try:
            cc_hourly_obj = get_hourly.result()
        except:
            print(
                'Exception occurred during cc_hourly_obj API call: {}'.format(
                    sys.exc_info()))
            if flask_app:
                flask_app.logger.error(
                    'Exception occurred during cc_hourly_obj API call: {}'.
                    format(sys.exc_info()[0]))
            cc_hourly_obj = None
        #  If this request failed, return an empty dictionary
        if not cc_hourly_obj:
            if input_dictionary:
                return input_dictionary
            else:
                return False

        try:
            cc_daily_obj = get_daily.result()
        except:
            print('Exception occurred during cc_daily_obj API call: {}'.format(
                sys.exc_info()))
            if flask_app:
                flask_app.logger.error(
                    'Exception occurred during cc_daily_obj API call: {}'.
                    format(sys.exc_info()[0]))
            cc_daily_obj = None
        #  If this request failed, return an empty dictionary
        if not cc_daily_obj:
            if input_dictionary:
                return input_dictionary
            else:
                return False

    #  Use the input dictionary or build a new one if we didn't get one
    if input_dictionary:
        output = input_dictionary
    else:
        #  Create the output JSON structure
        tf = TimezoneFinder()
        output = {
            'latitude': latitude,
            'longitude': longitude,
            #  Climacell does not provide the timezone
            'timezone': tf.timezone_at(lat=latitude, lng=longitude),
            'currently': {},
            'minutely': {},
            'hourly': {},
            'daily': {},
            #  Climacell does not provide alerts to free accounts
            #'alerts': [],
            'flags': {
                'sources': [],
                'units': 'us'
            }
        }

        #  Set the system timezone so that all times are local relative to
        #  this lat/long
        os.environ['TZ'] = output['timezone']

        #  Calculate the timezone's offset from UTC in hours and add that
        #  to the output
        tz_now = datetime.datetime.now(pytz.timezone(output['timezone']))
        output['offset'] = tz_now.utcoffset().total_seconds() / 3600

    #--------------------------   C u r r e n t l y   --------------------------#

    #  Populate the output dictionary with the current observations
    if cc_current_obj:
        output['currently'] = {
            'time':
            functions.getKeyValue(cc_current_obj,
                                  ['observation_time', 'value'],
                                  lambda x: int(_epochTime(x))),
            'summary':
            functions.getKeyValue(cc_current_obj, ['weather_code', 'value'],
                                  lambda x: _mapClimacellWeatherCode(x)),
            'icon':
            functions.getKeyValue(cc_current_obj, ['weather_code', 'value'],
                                  lambda x: _mapIcons(x, flask_app)),
            #'nearestStormDistance': None,
            'precipIntensity':
            functions.getKeyValue(cc_current_obj, ['precipitation', 'value']),
            #'precipIntensityError': None,
            #'precipProbability': None,
            'precipType':
            functions.getKeyValue(cc_current_obj,
                                  ['precipitation_type', 'value'],
                                  lambda x: None if x == 'none' else x),
            'temperature':
            functions.getKeyValue(cc_current_obj, ['temp', 'value']),
            'apparentTemperature':
            functions.getKeyValue(cc_current_obj, ['feels_like', 'value']),
            'dewPoint':
            functions.getKeyValue(cc_current_obj, ['dewpoint', 'value']),
            'humidity':
            functions.getKeyValue(cc_current_obj, ['humidity', 'value'],
                                  lambda x: round(x / 100)),
            'pressure':
            functions.getKeyValue(cc_current_obj, ['baro_pressure', 'value']),
            'windSpeed':
            functions.getKeyValue(cc_current_obj, ['wind_speed', 'value']),
            'windGust':
            functions.getKeyValue(cc_current_obj, ['wind_gust', 'value']),
            'windBearing':
            functions.getKeyValue(cc_current_obj, ['wind_direction', 'value']),
            'cloudCover':
            functions.getKeyValue(cc_current_obj, ['cloud_cover', 'value'],
                                  lambda x: round(x / 100)),
            #'uvIndex': None,
            'visibility':
            functions.getKeyValue(cc_current_obj, ['visibility', 'value']),
            'ozone':
            functions.getKeyValue(cc_current_obj, ['o3', 'value']),
        }

    #---------------------------   M i n u t e l y   ---------------------------#

    #  Add the minutely data from Climacell to the output dictionary
    if cc_minutely_obj:
        minutely_data = functions.getKeyValue(output, ['minutely', 'data'])

        #  If we already have minutely data, we won't change it.  We  only
        #  use our data when there isn't anything already in place.
        if not minutely_data or len(minutely_data) == 0:
            minutely_data = []
            for minute in cc_minutely_obj:
                minutely_data.append({
                    'time':
                    _epochTime(minute['observation_time']['value']),
                    'precipIntensity':
                    functions.getKeyValue(minute, ['precipitation', 'value']),
                    #  Climacell doesn't provide these next two elements
                    #  in their minute-by-minute forecast
                    'precipIntesityError':
                    None,
                    'precipProbability':
                    None,
                    'precipType':
                    functions.getKeyValue(minute,
                                          ['precipitation_type', 'value'],
                                          lambda x: None if x == 'none' else x)
                })

            output['minutely'] = {
                'summary': None,
                'icon': None,
                'data': minutely_data
            }

    #-----------------------------   H o u r l y   -----------------------------#

    #  Add the hourly data from Climacell to the output dictionary
    if cc_hourly_obj:
        hourly_data = functions.getKeyValue(output, ['hourly', 'data'])

        #  If there's no hourly data then create an hourly data array
        #  with just a timestamp for each day
        if not hourly_data or len(hourly_data) == 0:
            hourly_data = []
            timestamp = int(
                datetime.datetime.combine(
                    datetime.date.today(),
                    datetime.time(datetime.datetime.now().hour)).timestamp())
            for timestamp in range(timestamp + (timestamp + (3600 * 48)),
                                   3600):
                hourly_data.append({'time': int(timestamp)})

        #  Add the Climacell data for each day
        for i in range(len(hourly_data)):
            hour = hourly_data[i]
            cc_hour = cc_hourly_obj[i]
            if hour['time'] == _epochTime(
                    cc_hour['observation_time']['value']):
                hourly_data[i] = {
                    'time':
                    hour['time'],
                    'summary':
                    functions.getKeyValue(
                        cc_hour, ['weather_code', 'value'],
                        lambda x: _mapClimacellWeatherCode(x)),
                    'icon':
                    functions.getKeyValue(cc_hour, ['weather_code', 'value'],
                                          lambda x: _mapIcons(x, flask_app)),
                    #'nearestStormDistance': None,
                    'precipIntensity':
                    functions.getKeyValue(cc_hour, ['precipitation', 'value']),
                    #'precipIntensityError': None,
                    'precipProbability':
                    functions.getKeyValue(
                        cc_hour, ['precipitation_probability', 'value'],
                        lambda x: round(x / 100, 2)),
                    'precipType':
                    functions.getKeyValue(cc_hour,
                                          ['precipitation_type', 'value'],
                                          lambda x: None
                                          if x == 'none' else x),
                    'temperature':
                    functions.getKeyValue(cc_hour, ['temp', 'value']),
                    'apparentTemperature':
                    functions.getKeyValue(cc_hour, ['feels_like', 'value']),
                    'dewPoint':
                    functions.getKeyValue(cc_hour, ['dewpoint', 'value']),
                    'humidity':
                    functions.getKeyValue(cc_hour, ['humidity', 'value'],
                                          lambda x: round(x / 100, 2)),
                    'pressure':
                    functions.getKeyValue(cc_hour, ['baro_pressure', 'value']),
                    'windSpeed':
                    functions.getKeyValue(cc_hour, ['wind_speed', 'value']),
                    'windGust':
                    functions.getKeyValue(cc_hour, ['wind_gust', 'value']),
                    'windBearing':
                    functions.getKeyValue(cc_hour,
                                          ['wind_direction', 'value']),
                    'cloudCover':
                    functions.getKeyValue(cc_hour, ['cloud_cover', 'value'],
                                          lambda x: round(x / 100, 2)),
                    #'uvIndex': None,
                    'visibility':
                    functions.getKeyValue(cc_hour, ['visibility', 'value']),
                    'ozone':
                    functions.getKeyValue(cc_hour, ['o3', 'value'])
                }

            #  Use data from the first hour as the summary values for this
            #  section and the minutely section
            output['hourly']['summary'] = hourly_data[0]['summary']
            output['hourly']['icon'] = hourly_data[0]['icon']
            output['minutely']['summary'] = hourly_data[0]['summary']
            output['minutely']['icon'] = hourly_data[0]['icon']

        #  Put the hourly data into the output dictionary
        output['hourly']['data'] = hourly_data

    #------------------------------   D a i l y   ------------------------------#

    #  Add the daily data from Climacell to the output directory
    if cc_daily_obj:
        daily_data = functions.getKeyValue(output, ['daily', 'data'])

        #  If there's no daily data then create a daily data array
        #  with just a timestamp for each day
        if not daily_data or len(daily_data) == 0:
            daily_data = []
            d = datetime.datetime.utcnow()
            timestamp = int(
                datetime.datetime(d.year,
                                  d.month,
                                  d.day,
                                  0,
                                  0,
                                  0,
                                  tzinfo=datetime.timezone.utc).timestamp())
            for timestamp in range(timestamp, timestamp + (86400 * 8), 86400):
                daily_data.append({'time': int(timestamp)})

        #  If there are less than 8 days in the array, add the missing
        #  days with just a timestamp value
        if len(daily_data) < 8:
            timestamp = daily_data[len(daily_data) - 1]['time']
            for i in range(8 - len(daily_data)):
                timestamp = timestamp + 86400
                daily_data.append({'time': timestamp})

        #  Align the dates in the two arrays
        ctr = 0
        for i in range(len(cc_daily_obj)):
            if _dailyEpochTime(cc_daily_obj[ctr]['observation_time']
                               ['value']) < daily_data[0]['time']:
                ctr = ctr + 1

        #  Update the data for each day
        for i in range(len(daily_data)):
            day = daily_data[i]
            cc_day = cc_daily_obj[ctr]
            daily_data[i] = {
                'time':
                day['time'],
                'summary':
                functions.getKeyValue(cc_day, ['weather_code', 'value'],
                                      lambda x: _mapClimacellWeatherCode(x)),
                'icon':
                functions.getKeyValue(cc_day, ['weather_code', 'value'],
                                      lambda x: _mapIcons(x, flask_app)),
                #'nearestStormDistance': None,
                'sunriseTime':
                functions.getKeyValue(
                    cc_day, ['sunrise', 'value'],
                    lambda x: round(isodate.parse_datetime(x).timestamp())),
                'sunsetTime':
                functions.getKeyValue(
                    cc_day, ['sunset', 'value'],
                    lambda x: round(isodate.parse_datetime(x).timestamp())),
                #  Climacell provides text moon phase names and we want
                #  the fractional part of the lunation number instead
                #  so we'll calculate this outselves using Astral
                'moonPhase':
                round(
                    moon.phase(datetime.datetime.utcfromtimestamp(day['time']))
                    / 27.99, 2),
                'precipIntensity':
                functions.getKeyValue(cc_day,
                                      ['precipitation', 0, 'max', 'value']),
                'precipIntensityMax':
                functions.getKeyValue(cc_day,
                                      ['precipitation', 0, 'max', 'value']),
                'precipIntensityMaxTime':
                functions.getKeyValue(
                    cc_day, ['precipitation', 'observation_time'],
                    lambda x: int(isodate.parse_datetime(x).timestamp())),
                'precipProbability':
                functions.getKeyValue(cc_day,
                                      ['precipitation_probability', 'value']),
                #'precipType': None,
                'temperatureHigh':
                None,
                'temperatureHighTime':
                None,
                'temperatureLow':
                None,
                'temperatureLowTime':
                None,
                'apparentTemperatureHigh':
                None,
                'apparentTemperatureHighTime':
                None,
                'apparentTemperatureLow':
                None,
                'apparentTemperatureLowTime':
                None,
                'dewPoint':
                None,
                'humidity':
                None,
                'pressure':
                None,
                #  Climacell does not provide, using data from input array, if any
                'windSpeed':
                functions.getKeyValue(day, ['windSpeed']),
                'windGust':
                None,
                'windGustTime':
                None,
                #  Climacell does not provide, using data from input array, if any
                'windBearing':
                functions.getKeyValue(day, ['windBearing']),
                #  Climacell does not provide, using data from input array, if any
                'cloudCover':
                functions.getKeyValue(day, ['cloudCover']),
                #'uvIndex': None,
                #'uvIndexTime', None,
                #  Climacell does not provide, using data from input array, if any
                'visibility':
                functions.getKeyValue(day, ['visibility']),
                #'ozone': None,
                'temperatureMin':
                None,
                'temperatureMinTime':
                None,
                'temperatureMax':
                None,
                'temperatureMaxTime':
                None,
                'apparentTemperatureMin':
                None,
                'apparentTemperatureMinTime':
                None,
                'apparentTemperatureMax':
                None,
                'apparentTemperatureMaxTime':
                None
            }

            #  Get min and max temperatures from the Climacell data array and plug them in
            for t in cc_day['temp']:
                if 'min' in t:
                    daily_data[i]['temperatureLow'] = t['min']['value']
                    daily_data[i]['temperatureLowTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
                    daily_data[i]['temperatureMin'] = t['min']['value']
                    daily_data[i]['temperatureMinTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
                if 'max' in t:
                    daily_data[i]['temperatureHigh'] = t['max']['value']
                    daily_data[i]['temperatureHighTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
                    daily_data[i]['temperatureMax'] = t['max']['value']
                    daily_data[i]['temperatureMaxTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
            for t in cc_day['feels_like']:
                if 'min' in t:
                    daily_data[i]['apparentTemperatureLow'] = t['min']['value']
                    daily_data[i]['apparentTemperatureLowTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
                    daily_data[i]['apparentTemperatureMin'] = t['min']['value']
                    daily_data[i]['apparentTemperatureMinTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
                if 'max' in t:
                    daily_data[i]['apparentTemperatureHigh'] = t['max'][
                        'value']
                    daily_data[i]['apparentTemperatureHighTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())
                    daily_data[i]['apparentTemperatureMax'] = t['max']['value']
                    daily_data[i]['apparentTemperatureMaxTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())

            #  Get the average of the min and max humidity and use
            #  that for the daily value
            for t in cc_day['humidity']:
                total = 0
                if 'min' in t:
                    total = total + t['min']['value']
                if 'max' in t:
                    total = total + t['max']['value']
                daily_data[i]['humidity'] = round(
                    total / len(cc_day['humidity']), 2)

            #  Get the average of the min and max barometric pressure
            #  and use that for the daily value
            for t in cc_day['baro_pressure']:
                total = 0
                if 'min' in t:
                    total = total + t['min']['value']
                if 'max' in t:
                    total = total + t['max']['value']
                daily_data[i]['pressure'] = round(
                    total / len(cc_day['baro_pressure']), 2)

            #  Get the max wind speed and plug that in as windGust
            for t in cc_day['wind_speed']:
                if 'max' in t:
                    daily_data[i]['windGust'] = t['max']['value']
                    daily_data[i]['windGustTime'] = int(
                        isodate.parse_datetime(
                            t['observation_time']).timestamp())

            ctr = ctr + 1

        #  Use data from the first day as the summary values for this
        #  section
        output['daily']['summary'] = daily_data[0]['summary']
        output['daily']['icon'] = daily_data[0]['icon']

        #  Put the daily data into the output dictionary
        output['daily']['data'] = daily_data

    #-----------------------------   A l e r t s   -----------------------------#
    '''
	Climacell's alerts are a proprietary messaging system, not weather
	alerts. If the input data structure included NOAA weather alerts,
	those will be passed through untouched.
	'''

    #  Add a source flag for this source
    sources = []
    if functions.getKeyValue(input_dictionary, ['flags', 'sources']):
        for source in functions.getKeyValue(input_dictionary,
                                            ['flags', 'sources']):
            sources.append(source)
    sources.append('climacell')
    output['flags']['sources'] = sources

    return output
Пример #18
0
 async def async_update(self):
     """Get the time and updates the states."""
     today = dt_util.as_local(dt_util.utcnow()).date()
     self._state = moon.phase(today)