def __init__(self, bot): self.bot = bot self.astral = astral.Astral() self.zodiac = ( (120, '\N{CAPRICORN}'), (218, '\N{AQUARIUS}'), (320, '\N{PISCES}'), (420, '\N{ARIES}'), (521, '\N{TAURUS}'), (621, '\N{GEMINI}'), (722, '\N{CANCER}'), (823, '\N{LEO}'), (923, '\N{VIRGO}'), (1023, '\N{LIBRA}'), (1122, '\N{SCORPIUS}'), (1222, '\N{SAGITTARIUS}'), (1231, '\N{CAPRICORN}'), ) self.moon_phases = ( (0, '\N{NEW MOON SYMBOL}'), (4, '\N{WAXING CRESCENT MOON SYMBOL}'), (7, '\N{FIRST QUARTER MOON SYMBOL}'), (11, '\N{WAXING GIBBOUS MOON SYMBOL}'), (14, '\N{FULL MOON SYMBOL}'), (18, '\N{WANING GIBBOUS MOON SYMBOL}'), (21, '\N{LAST QUARTER MOON SYMBOL}'), (26, '\N{WANING CRESCENT MOON SYMBOL}'), )
def __init__(self, *args, location=None): """An object inheriting from dict, storing solar hours for a location. Parameters ---------- location : astral.Location or tuple, optional Allows you to provide a location, allowing an automatic getting of solar hours. Must be an 'astral.Location' object or a tuple like '(latitude, longitude, timezone_name, elevation)'. None default, meaning it relies only on manual settings. Although this is mostly intended for manual testing, you can also use one of the capital/city names supported by Astral, like "London" or "Copenhagen". Attributes ---------- location : astral.Location or None The location for which to get solar hours. To manually set solar hours for the present day, do the following: >>> solar_hours[datetime.date.today()] = {...} """ if isinstance(location, astral.Location): self.location = location elif isinstance(location, tuple): self.location = astral.Location(["Location", "Region", *location]) elif isinstance(location, str): self.location = astral.Astral()[location] else: self.location = None super().__init__(*args)
def __init__(self, dt): """constructor. Creates a new Forecast object, and instantiates Weather objects to display the current weather along with daily and hourly forecasts, as well objects to display the news and advertisements. Args: dt (datetime.datetime): the current datetime, i.e. datetime.datetime.now() """ self.dt = dt self.astral = astral.Astral() self.astral_city = 'Chicago' self.current_weather = CurrentWeather(dt) self.daily = [] d = self.current_weather.dt.replace(hour=0, minute=0, second=0) for i in range(1, 7): self.daily.append(DailyWeather(d + datetime.timedelta(days=i))) self.hourly = [] d = self.current_weather.dt.replace(minute=0, second=0) for i in range(1, 25): self.hourly.append(HourlyWeather(d + datetime.timedelta(hours=i))) self.news = News()
def checkTime(self): """ use google to check the sun position time of day """ # check only if neccessary if self.checked and self.checked == time.strftime("%j"): return self.checked try: a = astral.Astral(astral.GoogleGeocoder) a.solar_depression = 'civil' city = a[self.place] self.dawn = int(city.sun(date=datetime.date.today(), local=True)['dawn'].strftime('%s')) self.sunrise = int(city.sun(date=datetime.date.today(), local=True)['sunrise'].strftime('%s')) self.sunset = int(city.sun(date=datetime.date.today(), local=True)['sunset'].strftime('%s')) self.dusk = int(city.sun(date=datetime.date.today(), local=True)['dusk'].strftime('%s')) except Exception as err: self.checked = None self.checked = str(err) self.dawn = 1 self.dusk = 2 self.sunrise = 3 self.sunset = 4 else: self.checked = time.strftime("%j") return self.checked
def _create_solar_context(self,forecast_days, solar_file, w_forcast_err, city): solar_panel_config = {'voltage_t': 7.32, 'area_j': 0.0165, 'efficiency_j': 0.15} dfx = pd.read_csv(solar_file, index_col=0,parse_dates=True) a = astral.Astral() location = a[city] lat = location.latitude lon = location.longitude dfx['zenith'] =dfx.index.to_series().apply(lambda timestamp: a.solar_zenith(timestamp, lat, lon)) dfx['zenith']= (dfx['zenith'] - dfx['zenith'].mean())/dfx['zenith'].std() dfx['azimuth'] =dfx.index.to_series().apply(lambda timestamp: a.solar_azimuth(timestamp, lat, lon)) dfx['azimuth']= (dfx['azimuth'] - dfx['azimuth'].mean())/dfx['azimuth'].std() dfx.loc[dfx.index[0]-pd.to_timedelta(1, unit='h')] = dfx.loc[dfx.index[-1]] dfx = dfx.sort_index()[:-1] area = solar_panel_config['area_j'] efficiency = solar_panel_config['efficiency_j'] dfx['e_harvest'] = dfx['a']*area*1E9*efficiency/(60*60) dfx['w_forecast'] = np.random.uniform(low=(dfx['a']-(dfx['a']*w_forcast_err)), high=(dfx['a']+(dfx['a']*w_forcast_err))) dfx['w_forecast'] = dfx['w_forecast']*area*1E9*efficiency/(60*60) dfx.drop('a', axis=1, inplace=True) forecast_day= dfx['w_forecast'].resample('D').sum() daterange = forecast_day.index for i in range(forecast_days): forecast_day.loc[forecast_day.index[-1]+1*daterange.freq]= forecast_day.loc[forecast_day.index[i]] forecast= forecast_day.rolling(str(forecast_days)+'D').sum().shift(-(forecast_days-1))[:-forecast_days] return {'dataframe': dfx, 'w_forecast': forecast}
def make_nightsky(self): a = astral.Astral() tomorrow = self.dt + timedelta(days = 1) yesterday = self.dt - timedelta(days = 1) if self.dt > self.loc.sunset(self.dt.date()): moon_phase = a.moon_phase(self.dt.date()) night_length = self.loc.sunrise(tomorrow) - self.loc.sunset(self.dt.date()) night_so_far = self.dt - self.loc.sunset(self.dt.date()) elif self.dt < self.loc.sunrise(self.dt.date()): moon_phase = a.moon_phase(yesterday.date()) night_length = self.loc.sunrise(self.dt.date()) - self.loc.sunset(yesterday) night_so_far = self.dt - self.loc.sunset(yesterday) if moon_phase == 0: moon = MOONS[0] elif moon_phase < 7: moon = MOONS[1] elif moon_phase < 14: moon = MOONS[2] elif moon_phase == 14: moon = MOONS[3] elif moon_phase < 21: moon = MOONS[4] else: moon = MOONS[5] moon_placement = 14 - int((night_so_far.seconds/night_length.seconds) * 15) for _ in range(moon_placement): self.sky += u"\u2800" self.sky += moon + u"\uFE0F"
def sunset_sunrise(time, lat, lon): """ Uses the Astral package to find sunset and sunrise times. The times are returned rather than day or night indicies. More flexible for quenching corrections. """ ast = astral.Astral() df = pd.DataFrame.from_items([ ('time', time), ('lat', lat), ('lon', lon), ]) # set days as index df = df.set_index(df.time.values.astype('datetime64[D]')) # groupby days and find sunrise for unique days grp = df.groupby(df.index).mean() date = grp.index.to_pydatetime() grp['sunrise'] = list(map(ast.sunrise_utc, date, df.lat, df.lon)) grp['sunset'] = list(map(ast.sunset_utc, date, df.lat, df.lon)) # reindex days to original dataframe as night df[['sunrise', 'sunset']] = grp[['sunrise', 'sunset']].reindex(df.index) # set time as index again df = df.set_index('time', drop=False) cols = ['time', 'sunset', 'sunrise'] return df[cols]
def get_moon_phase(date): """ Get Moon Phase. """ ast = astral.Astral() phase_int = int(ast.moon_phase(date)) if phase_int == 0: phase = "New moon" elif phase_int <= 7: phase = "Waxing crescent" elif phase_int == 7: phase = "First quarter" elif 7 < phase_int < 14: phase = "Waxing gibbous" elif phase_int == 14: phase = "Full moon" elif 14 < phase_int < 21: phase = "Waning gibbous" elif phase_int == 21: phase = "Last quarter" elif 21 < phase_int < 28: phase = "Waning crescent" else: phase = "New moon" return phase
def getMoonPhase(self, cityName="Bangkok"): #0 = New moon, 7 = First quarter, 14 = Full moon, 21 = Last quarter a = astral.Astral() a.solar_depression = 'civil' city = a[cityName] return city.moon_phase(date=datetime.datetime.now( tz=pytz.timezone('Europe/Berlin')))
def get_google_geo(): # Use this to get google co-ords and elevation from astral.astral import GoogleGeocoder a = astral.Astral(astral.GoogleGeocoder) geo = a.geocoder loc = geo['Tel-Aviv'] print(loc, loc.elevation)
def stars_out(date=None, degrees=None): if not date: date = datetime.datetime.now() geo = astral.Astral(astral.AstralGeocoder).geocoder[LOCATION] if degrees is not None: geo.solar_depression = degrees dusk = geo.dusk(local=True, date=date) return dusk
def __init__(self, step=1, year=None): self.__a = astral.Astral() self.__sec_in_min = 60 self.__step = step self.__year = datetime.datetime.today().year if year is None else year self.__current_date = self.today() self.__current_date_copy = self.__current_date self.__ax = None
def sunSet(lat, lon, dayOffset=0): t = datetime.date.today() + datetime.timedelta(days=dayOffset) a = astral.Astral() utc = a.sunset_utc(t, lat, lon) # Convert the UTC datetime to a UNIX time stamp. return calendar.timegm(utc.timetuple())
def day_night_background(self, dsname=None, subplot_index=(0, )): """ Colorcodes the background according to sunrise/sunset Parameters ---------- dsname: None or str If there is more than one datastream in the display object the name of the datastream needs to be specified. If set to None and there is only one datastream then ACT will use the sole datastream in the object. subplot_index: 1 or 2D tuple, list, or array The index to the subplot to place the day and night background in. """ if dsname is None and len(self._arm.keys()) > 1: raise ValueError(("You must choose a datastream to derive the " + "information needed for the day and night " + "background when 2 or more datasets are in " + "the display object.")) elif dsname is None: dsname = self._arm.keys()[0] # Get File Dates file_dates = self._arm[dsname].act.file_dates if len(file_dates) == 0: sdate = dt_utils.numpy_to_arm_date(self._arm[dsname].time.values[0]) edate = dt_utils.numpy_to_arm_date(self._arm[dsname].time.values[-1]) file_dates = [sdate, edate] all_dates = dt_utils.dates_between(file_dates[0], file_dates[-1]) if self.axes is None: raise RuntimeError("day_night_background requires the plot to be displayed.") ax = self.axes[subplot_index] # initialize the plot to a gray background for total darkness rect = ax.patch rect.set_facecolor('0.85') # Initiate Astral Instance a = astral.Astral() if self._arm[dsname].lat.data.size > 1: lat = self._arm[dsname].lat.data[0] lon = self._arm[dsname].lon.data[0] else: lat = float(self._arm[dsname].lat.data) lon = float(self._arm[dsname].lon.data) for f in all_dates: sun = a.sun_utc(f, lat, lon) # add yellow background for specified time period ax.axvspan(sun['sunrise'], sun['sunset'], facecolor='#FFFFCC') # add local solar noon line ax.axvline(x=sun['noon'], linestyle='--', color='y')
def __init__(self, location): """ Parameters ---------- location: String """ self.location = geocoder.google(location) self.elevation = geocoder.google(self.location.latlng, method='Elevation').elevation self.astral = astral.Astral()
def binary_daytime(samples_dt): city_name = 'Paris' a = astral.Astral() a.solar_depression = 'civil' city = a[city_name] sun = pd.DataFrame( list(map(lambda dd: city.sun(date=dd, local=False), samples_dt.date))) # This takes a lot of time !!! daylights = np.logical_and( samples_dt > sun['sunrise'], samples_dt < sun['sunset'], ).astype(int) return daylights
def sundata(self): now = datetime.datetime.now() if (self.suncache is not None): if (self.suncache.day >= now.day): return self.suncache = now a = astral.Astral() a.solar_depression = 'civil' sun = a['Copenhagen'].sun(now, local=True) self.dusk = sun['dusk'] self.dawn = sun['dawn'] self.sunrise = sun['sunrise'] self.sunset = sun['sunset']
def _updateSunAndMoon(self): now = datetime.datetime.now() a = astral.Astral() a.solar_depression = 'civil' city = a[self._LOCATION] sun = city.sun(date=datetime.date.today(), local=False) dawn = sun['dawn'].replace(tzinfo=None) + datetime.timedelta(hours=self._OFFSET) sunrise = sun['sunrise'].replace(tzinfo=None) + datetime.timedelta(hours=self._OFFSET) sunset = sun['sunset'].replace(tzinfo=None) + datetime.timedelta(hours=self._OFFSET) dusk = sun['dusk'].replace(tzinfo=None) + datetime.timedelta(hours=self._OFFSET) moon_phase = city.moon_phase(date=datetime.datetime.now(tz=pytz.timezone('Europe/Berlin'))) observer = ephem.Observer() observer.lon = self._LOGITUDE observer.lat = self._LATITUDE observer.elevation = self._ELEVATION observer.date = datetime.datetime.now(tz=pytz.timezone('Europe/Berlin')) moon = ephem.Moon(observer) moon_elevation = moon.alt * (180 / math.pi) if dawn < now < sunrise: duration = sunrise - dawn done = now - dawn self._day_state = DAWN self._sun_percentage = int((done.total_seconds() / duration.total_seconds()) * 100) elif sunrise < now < sunset: self._day_state = DAY self._sun_percentage = 100 elif sunset < now < dusk: duration = dusk - sunset done = now - sunset self._day_state = SUNSET self._sun_percentage = int((1.0 - (done.total_seconds() / duration.total_seconds())) * 100) else: self._day_state = NIGHT self._sun_percentage = 0 if 0 <= moon_phase <= 14: moon_phase_percentage = 1.0 - ( (14.0 - (moon_phase ) ) / 14.0) else: moon_phase_percentage = ( (14.0 - (moon_phase - 14.0) ) / 14.0) if moon_elevation > 0: self._moon_percentage = int(moon_phase_percentage * (moon_elevation / 90.0) * 100) else: self._moon_percentage = 0
def getSunTimes(self, cityName="Bangkok", offset=11): a = astral.Astral() a.solar_depression = 'civil' city = a[cityName] sun = city.sun(date=datetime.date.today(), local=False) dawn = sun['dawn'].replace(tzinfo=None) + datetime.timedelta( hours=offset) sunrise = sun['sunrise'].replace(tzinfo=None) + datetime.timedelta( hours=offset) noon = sun['noon'].replace(tzinfo=None) + datetime.timedelta( hours=offset) sunset = sun['sunset'].replace(tzinfo=None) + datetime.timedelta( hours=offset) dusk = sun['dusk'].replace(tzinfo=None) + datetime.timedelta( hours=offset) return dawn, sunrise, noon, sunset, dusk
def GetSunriseTime(day): a = astral.Astral() a.solar_depression = 'civil' l = astral.Location() l.name = '9WGJ+42 Mountain View California' l.region = 'USA' l.latitude = 37.375313 l.longitude = -122.069938 l.timezone = 'US/Pacific' l.elevation = 42.865 # Finding the next sunrise. sun = l.sun(day, local=True) return sun['sunrise']
def getSunRiseSet(): a = astral.Astral() brum = a['Birmingham'] now = datetime.datetime.now() sun = brum.sun(date=now) if sun['sunrise'].replace(tzinfo=None) < now: sunrise = sun['sunrise'] if sun['sunset'].replace(tzinfo=None) < now: sunset = sun['sunset'] else: sun = brum.sun(date=(now - datetime.timedelta(hours=24))) sunset = sun['sunset'] else: sun = brum.sun(date=(now - datetime.timedelta(hours=24))) sunrise = sun['sunrise'] sunset = sun['sunset'] return time.mktime(sunrise.timetuple()), time.mktime(sunset.timetuple())
def day_night_background(self, subplot_index=(0, )): """ Colorcodes the background according to sunrise/sunset Parameters ---------- subplot_index: 1 or 2D tuple, list, or array The index to the subplot to place the day and night background in. """ # Get File Dates file_dates = self._arm.act.file_dates if len(file_dates) == 0: sdate = dt_utils.numpy_to_arm_date(self._arm.time.values[0]) edate = dt_utils.numpy_to_arm_date(self._arm.time.values[-1]) file_dates = [sdate, edate] all_dates = dt_utils.dates_between(file_dates[0], file_dates[-1]) if self.axes is None: raise RuntimeError( "day_night_background requires the plot to be displayed.") ax = self.axes[subplot_index] # initialize the plot to a gray background for total darkness rect = ax.patch rect.set_facecolor('0.85') # Initiate Astral Instance a = astral.Astral() if self._arm.lat.data.size > 1: lat = self._arm.lat.data[0] lon = self._arm.lon.data[0] else: lat = float(self._arm.lat.data) lon = float(self._arm.lon.data) for f in all_dates: sun = a.sun_utc(f, lat, lon) # add yellow background for specified time period ax.axvspan(sun['sunrise'], sun['sunset'], facecolor='#FFFFCC') # add local solar noon line ax.axvline(x=sun['noon'], linestyle='--', color='y')
def _astral(self): """ print('Dawn: %s' % str(sun['dawn'])) print('Sunrise: %s' % str(sun['sunrise'])) print('Noon: %s' % str(sun['noon'])) print('Sunset: %s' % str(sun['sunset'])) print('Dusk: %s' % str(sun['dusk'])) :return: sun """ a = astral.Astral() a.solar_depression = 'nautical' city = astral.Location(('Home', None, 54, 83, 'Asia/Novosibirsk', 0)) # print('Information for %s/%s\n' % ('Novosibirsk', city.region)) # print('Timezone: %s' % city.timezone) # print('Latitude: %.02f; Longitude: %.02f\n' % (city.latitude, city.longitude)) sun = city.sun(date=datetime.date.today() + datetime.timedelta(days=1), local=True) return sun
def get_moon(): a = astral.Astral() moon_phase = a.moon_phase(utcdt, rtype=float) lunation = moon_phase / 27.99 PRECISION = 0.05 NEW = 0 / 4.0 FIRST = 1 / 4.0 FULL = 2 / 4.0 LAST = 3 / 4.0 NEXTNEW = 4 / 4.0 phase_strings = ((NEW + PRECISION, "🌑"), (FIRST - PRECISION, "🌒"), (FIRST + PRECISION, "🌓"), (FULL - PRECISION, "🌔"), (FULL + PRECISION, "🌕"), (LAST - PRECISION, "🌖"), (LAST + PRECISION, "🌗"), (NEXTNEW - PRECISION, "🌘"), (NEXTNEW + PRECISION, "🌑")) i = bisect.bisect([a[0] for a in phase_strings], lunation) return phase_strings[i][1]
def sundata(self): a = astral.Astral() a.solar_depression = 'civil' sun = a['Copenhagen'].sun(datetime.datetime.now(), local=True) dusk = sun['dusk'] dawn = sun['dawn'] sunrise = sun['sunrise'] sunset = sun['sunset'] #pdb.set_trace() dusks = int( abs((dusk - dusk.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds())) dawns = int( abs((dawn - dawn.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds())) sunss = int( abs((sunset - sunset.replace( hour=0, minute=0, second=0, microsecond=0)).total_seconds())) sunrs = int( abs((sunrise - sunrise.replace( hour=0, minute=0, second=0, microsecond=0)).total_seconds())) return sunrs, sunss, dusks, dawns
def _moon_phase(date_range: DatetimeIndex) -> Series: almanac = astral.Astral() return Series([almanac.moon_phase(date) for date in date_range], index=date_range)
import datetime import astral import pytz import time import motor from twilio.rest import Client import RPi.GPIO as GPIO account_sid = 'mytwiliosid' auth_token = 'mytwiliotoken' client = Client(account_sid, auth_token) a = astral.Astral() city_name = 'Omaha' city = a[city_name] timezone = city.timezone sun = city.sun(date=datetime.date.today(), local=True) dt = datetime.datetime.now(tz=pytz.UTC) dt_central_now = dt.astimezone(pytz.timezone('US/Central')) delta = datetime.timedelta(seconds=20) test_sunset = dt_central_now + delta ##print('sunrise is: ', sunrise, 'today.') ##print('sunset is: ', sunset, 'today.') ##print(dt_central_now - sunrise) try: mode = 1 evening_message = 0 morning_message = 0
def day_night_background(self, dsname=None, subplot_index=(0, )): """ Colorcodes the background according to sunrise/sunset. Parameters ---------- dsname: None or str If there is more than one datastream in the display object the name of the datastream needs to be specified. If set to None and there is only one datastream then ACT will use the sole datastream in the object. subplot_index: 1 or 2D tuple, list, or array The index to the subplot to place the day and night background in. """ if dsname is None and len(self._arm.keys()) > 1: raise ValueError(("You must choose a datastream to derive the " + "information needed for the day and night " + "background when 2 or more datasets are in " + "the display object.")) elif dsname is None: dsname = list(self._arm.keys())[0] # Get File Dates file_dates = self._arm[dsname].act.file_dates if len(file_dates) == 0: sdate = dt_utils.numpy_to_arm_date( self._arm[dsname].time.values[0]) edate = dt_utils.numpy_to_arm_date( self._arm[dsname].time.values[-1]) file_dates = [sdate, edate] all_dates = dt_utils.dates_between(file_dates[0], file_dates[-1]) if self.axes is None: raise RuntimeError("day_night_background requires the plot to " "be displayed.") ax = self.axes[subplot_index] # initialize the plot to a gray background for total darkness rect = ax.patch rect.set_facecolor('0.85') # Find variable names for latitude and longitude variables = list(self._arm[dsname].data_vars) lat_name = [var for var in ['lat', 'latitude'] if var in variables] lon_name = [var for var in ['lon', 'longitude'] if var in variables] if len(lat_name) == 0: lat_name = None else: lat_name = lat_name[0] if len(lon_name) == 0: lon_name = None else: lon_name = lon_name[0] # Variable name does not match, look for standard_name declaration if lat_name is None or lon_name is None: for var in variables: try: if self._arm[dsname][var].attrs['standard_name'] == 'latitude': lat_name = var except KeyError: pass try: if self._arm[dsname][var].attrs['standard_name'] == 'longitude': lon_name = var except KeyError: pass if lat_name is not None and lon_name is not None: break if lat_name is None or lon_name is None: return try: if self._arm[dsname].lat.data.size > 1: lat = self._arm[dsname][lat_name].data[0] lon = self._arm[dsname][lon_name].data[0] else: lat = float(self._arm[dsname][lat_name].data) lon = float(self._arm[dsname][lon_name].data) except AttributeError: return # Initiate Astral Instance a = astral.Astral() # Set the the number of degrees the sun must be below the horizon # for the dawn/dusk calculation. Need to do this so when the calculation # sends an error it is not going to be an inacurate switch to setting # the full day. a.solar_depression = 0 for f in all_dates: # Loop over previous, current and following days to cover all overlaps # due to local vs UTC times. for ii in [-1, 0, 1]: try: new_time = f + dt.timedelta(days=ii) sun = a.sun_utc(new_time, lat, lon) # add yellow background for specified time period ax.axvspan(sun['sunrise'], sun['sunset'], facecolor='#FFFFCC', zorder=0) # add local solar noon line ax.axvline(x=sun['noon'], linestyle='--', color='y', zorder=1) except astral.AstralError: # Error for all day and all night is the same. Check to see # if sun is above horizon at solar noon. If so plot. if a.solar_elevation(new_time, lat, lon) > 0: # Make whole background yellow for when sun does not reach # horizon. Use in high latitude locations. ax.axvspan(dt.datetime(f.year, f.month, f.day, hour=0, minute=0, second=0), dt.datetime(f.year, f.month, f.day, hour=23, minute=59, second=59), facecolor='#FFFFCC') # add local solar noon line ax.axvline(x=a.solar_noon_utc(f, lon), linestyle='--', color='y')
def test_Location_WithUnicodeLiteral(): a = astral.Astral() _l = a['London']
# ----- External Display support ----- # Set to True if you want to display METAR conditions to a small external display ACTIVATE_EXTERNAL_METAR_DISPLAY = True DISPLAY_ROTATION_SPEED = 6.0 # Float in seconds, e.g 2.0 for two seconds # --------------------------------------------------------------------------- # ------------END OF CONFIGURATION------------------------------------------- # --------------------------------------------------------------------------- print("Running metar.py at " + datetime.datetime.now().strftime('%d/%m/%Y %H:%M')) # Figure out sunrise/sunset times if astral is being used if astral is not None and USE_SUNRISE_SUNSET: try: # For older clients running python 3.5 which are using Astral 1.10.1 ast = astral.Astral() try: city = ast[LOCATION] except KeyError: print( "Error: Location not recognized, please check list of supported cities and reconfigure") else: print(city) sun = city.sun(date=datetime.datetime.now().date(), local=True) BRIGHT_TIME_START = sun['sunrise'].time() DIM_TIME_START = sun['sunset'].time() except AttributeError: # newer Raspberry Pi versions using Python 3.6+ using Astral 2.2 import astral.geocoder import astral.sun try: