def test_get_next_sun_event_time_and_type_happy() -> None: observer = astral.Observer() now = datetime.datetime(year=2000, month=1, day=1, hour=0, tzinfo=datetime.timezone.utc) date, type = get_next_sun_event_time_and_type(observer, now) assert date == datetime.datetime(2000, 1, 1, 8, 5, 57, 311165, tzinfo=datetime.timezone.utc) assert type == solarblinds2.config.EventType.SUNRISE now = datetime.datetime(year=2000, month=1, day=1, hour=12, tzinfo=datetime.timezone.utc) date, type = get_next_sun_event_time_and_type(observer, now) assert date == datetime.datetime(2000, 1, 1, 16, 0, 49, 698951, tzinfo=datetime.timezone.utc) assert type == solarblinds2.config.EventType.SUNSET
def test_get_next_sun_event_time_and_type_close_to_event() -> None: observer = astral.Observer() now = datetime.datetime(2000, 1, 1, 8, 5, 57, 311165 - 1, tzinfo=datetime.timezone.utc) date, type = get_next_sun_event_time_and_type(observer, now) assert date == datetime.datetime(2000, 1, 1, 8, 5, 57, 311165, tzinfo=datetime.timezone.utc) assert type == solarblinds2.config.EventType.SUNRISE now = datetime.datetime(2000, 1, 1, 8, 5, 57, 311165, tzinfo=datetime.timezone.utc) date, type = get_next_sun_event_time_and_type(observer, now) assert date == datetime.datetime(2000, 1, 1, 16, 0, 49, 698951, tzinfo=datetime.timezone.utc) assert type == solarblinds2.config.EventType.SUNSET now = datetime.datetime(2000, 1, 1, 8, 5, 57, 311165 + 1, tzinfo=datetime.timezone.utc) date, type = get_next_sun_event_time_and_type(observer, now) assert date == datetime.datetime(2000, 1, 1, 16, 0, 49, 698951, tzinfo=datetime.timezone.utc) assert type == solarblinds2.config.EventType.SUNSET
def func(self): """Show server time data in a table.""" lat, lon, ele = 33.43, -112.07, 24 here = self.character.location if here: x = float(here.tags.get(category="coordx", default=0)) y = float(here.tags.get(category="coordy", default=0)) # z = here.tags.get(category="coordz") if x and y: lat, lon = float(y/10000), float(x/10000) print('Using location coordinates: {}, {}'.format(lat, lon)) place = astral.LocationInfo(timezone='UTC', latitude=lat, longitude=lon) obsr = astral.Observer(latitude=lat, longitude=lon, elevation=ele) def time_dif(at, when): diff = abs(at - when) return 'now' if diff.total_seconds() < 60 else (utils.time_format(diff.total_seconds(), 2) + (' ago' if at > when else '')) def moon_phase(days): """ Summarize the visible portion, given days into cycle Args: days (int or float): days into current cycle Returns: phase (str): summary of view of visible portion """ phases = ('new', 'waxing crescent', 'First quarter', 'waxing gibbous', 'full', 'waning gibbous', 'last quarter', 'waning crescent') percent = float((float(days) + 0.5) / 29.53) phase = int((percent - int(percent)) * len(phases)) return phases[phase] try: sun = astral.sun.sun(date=datetime.date.today(), observer=obsr) except Exception as e: return else: past = here.tags.get('past', category='realm') moon = astral.moon.phase(date=datetime.date.today()) now = timezone.now() moment = ['dawn', 'sunrise', 'noon', 'sunset', 'dusk'] events = zip([each.capitalize() + ':' for each in moment], [time_dif(now, sun[each]) for each in moment]) table1 = EvTable("|wServer", '|wtime', align='l', width=75) table1.add_row('Current uptime', utils.time_format(gametime.uptime(), 3)) table1.add_row('First start', time_dif(datetime.datetime.now(), datetime.datetime.fromtimestamp(gametime.server_epoch()))) if here.tags.get('past', category='realm'): table1.add_row('Moon phase', moon_phase(moon)) table1.reformat_column(0, width=20) up = self.cmdstring == 'uptime' # User asking for uptime mode self.msg(('Current uptime: ' + utils.time_format(gametime.uptime(), 3)) if up else str(table1)) if past: # Astral events are to be displayed while in past realm table2 = EvTable("|wEvent", "|wTime until", align="l", width=75) for entry in events: table2.add_row(entry[0], entry[1]) table2.reformat_column(0, width=20) self.msg(str(table2) if self.cmdstring == 'events' else ('\n' + str(table2)))
def is_it_light_outside(): t = astral_sun(astral.Observer(MY_LAT, MY_LON), date=datetime.date.today()) tolerance = datetime.timedelta(minutes=45) sunrise = t['sunrise'] + tolerance sunset = t['sunset'] - tolerance ahora = datetime.datetime.now(t['sunset'].tzinfo) sun_out = ahora > sunrise and ahora < sunset return sun_out
def is_it_late_night(): t = astral_sun(astral.Observer(MY_LAT, MY_LON), date=datetime.date.today()) sunset = t['dusk'] next_sunrise = t['sunrise'] + datetime.timedelta(hours=24) ahora = datetime.datetime.now(t['sunset'].tzinfo) if ahora < sunset: return False if ahora > sunset and ahora < next_sunrise: local_hour = datetime.datetime.now().hour # no tz, just local hour if local_hour >= LATE_NIGHT_START_HOUR or local_hour <= next_sunrise.hour: return True return False
def load_config(config_file: typing.Union[str, pathlib.Path]) -> Configuration: with open(config_file) as f: config = yaml.safe_load(f)["configuration"] config["connection"] = ConnectionData(**config["connection"]) config["login"] = LoginData(**config["login"]) config["observer"] = astral.Observer(**config["observer"]) config["events"] = { EventType[key]: Event( delay=datetime.timedelta(seconds=event["delay_s"]), commands=[CommandData(**command) for command in event["commands"]], ) for key, event in config["events"].items() } return Configuration(**config)
def __init__( self, date=dt.datetime.now(), location=Location(), hebrew=True, candle_lighting_offset=18, havdalah_offset=0, ): """ Initialize the Zmanim object. As the timezone is expected to be part of the location object, any tzinfo passed along is discarded. Essentially making the datetime object non-timezone aware. The time zone information is appended to the date received based on the location object. After which it is transformed to UTC for all internal calculations. """ self.location = location self.hebrew = hebrew self.candle_lighting_offset = candle_lighting_offset self.havdalah_offset = havdalah_offset # If a non-timezone aware date is received, use timezone from location # to make it timezone aware and change to UTC for calculations. # If timezone aware is received as date, we expect it to match the # timezone specified by location, so it can be overridden and changed # to UTC for calculations as above. if isinstance(date, dt.datetime): _LOGGER.debug("Date input is of type datetime: %r", date) self.date = date.date() self.time = date.replace(tzinfo=None) elif isinstance(date, dt.date): _LOGGER.debug("Date input is of type date: %r", date) self.date = date self.time = dt.datetime.now() else: raise TypeError _LOGGER.debug("Resetting timezone to UTC for calculations") self.time = location.timezone.localize(self.time).astimezone(pytz.utc) if _USE_ASTRAL: self.astral_observer = astral.Observer( latitude=self.location.latitude, longitude=self.location.longitude ) self.astral_sun = astral.sun.sun(self.astral_observer, self.date)
def test_NorwaySunUp(): """Test location in Norway where the sun doesn't set in summer.""" june = datetime(2019, 6, 5, tzinfo=pytz.utc) obs = astral.Observer(69.6, 18.8, 0.0) with pytest.raises(ValueError): sun.sunrise(obs, june) with pytest.raises(ValueError): sun.sunset(obs, june) # Find the next sunset and sunrise: next_sunrise = _next_event(obs, june, "sunrise") next_sunset = _next_event(obs, june, "sunset") assert next_sunset < next_sunrise
def test_loop(do_command_mock: mock.MagicMock) -> None: mock_config = mock.Mock() mock_config.observer = astral.Observer() mock_config.events = { config.EventType.SUNRISE: config.Event(datetime.timedelta(), [config.CommandData(1, 0, 0, 0)]), config.EventType.SUNSET: config.Event(datetime.timedelta(), [config.CommandData(2, 0, 0, 0)]), } sb = solarblinds2.Solarblinds2(mock_config) sb.run() do_command_mock.assert_has_calls([ mock.call(config.CommandData(pid=2, oid=0, did=0, value=0)), mock.call(config.CommandData(pid=1, oid=0, did=0, value=0)), mock.call(config.CommandData(pid=2, oid=0, did=0, value=0)), mock.call(config.CommandData(pid=1, oid=0, did=0, value=0)), mock.call(config.CommandData(pid=2, oid=0, did=0, value=0)), ])
def set_location(latitude, longitude): global local_stations global local_radolan_idx global observer # Find 2 local forecast stations api = Wetterdienst(provider = 'dwd', kind = 'forecast') stations = api(parameter="large", mosmix_type=DwdMosmixType.LARGE) local_stations = stations.filter_by_rank(latitude=latitude, longitude=longitude, rank=2) # Determine local index in the radolan grid proj_stereo = wrl.georef.create_osr("dwd-radolan") proj_wgs = osr.SpatialReference() proj_wgs.ImportFromEPSG(4326) radolan_grid_xy = wrl.georef.get_radolan_grid(900, 900) coord_xy = wrl.georef.reproject([longitude, latitude], projection_source=proj_wgs, projection_target=proj_stereo) distance_xy = np.hypot(radolan_grid_xy[:, :, 0] - coord_xy[0], radolan_grid_xy[:, :, 1] - coord_xy[1]) local_radolan_idx = np.argwhere(distance_xy < 10) # Define observer for sun position observer = astral.Observer(latitude=latitude, longitude=longitude)
def pull_weather(self): r = requests.get('https://api.openweathermap.org/data/2.5/weather', params={ 'lat':self.lat, 'lon':self.lon, 'appid': self.key,} ) r.raise_for_status() request_data = r.json() self.data = {} self.data['temperature'] = request_data['main']['temp'] self.data['clouds'] = request_data['clouds']['all'] self.data['feels_like'] = request_data['main']['feels_like'] self.data['humidity'] = request_data['main']['humidity'] self.data['pressure'] = request_data['main']['pressure'] self.data['wind_deg'] = request_data['wind'].get('deg', 0) self.data['wind_speed'] = request_data['wind'].get('speed', 0) # data += f",dew_point={self.data['current']['dew_point']}" # data += f",uvi={self.data['current']['uvi']}" # data += f",wind_gust={self.data['current'].get('wind_gust', 0)}" if 'visibility' in request_data: self.data['visibility'] = request_data['visibility'] if 'rain' in request_data and '1h' in request_data['rain']: self.data['rain_1h'] = request_data['rain']['1h'] else: self.data['rain_1h'] = 0 if 'snow' in request_data and '1h' in request_data['snow']: self.data['snow_1h'] = request_data['snow']['1h'] else: self.data['snow_1h'] = 0 observer = astral.Observer(self.lat, self.lon) self.data['sun_elivation'] = astral.sun.elevation(observer) self.data['sun_azimuth'] = astral.sun.azimuth(observer) return self
def main(): args = parse_arguments() a = astral.Observer(latitude=args.latlong[0], longitude=args.latlong[1], elevation=args.altitude) thisday = datetime.datetime(args.year, args.month, args.day) lastday = thisday + datetime.timedelta(days=args.numdays) if args.icsfile: c = ics.Calendar() while thisday < lastday: suntime = astral.sun.time_at_elevation(a, date=thisday, elevation=args.elevation, tzinfo=args.timezone) print(suntime) thisday = thisday + datetime.timedelta(days=1) if args.icsfile: # TODO, add an argument for the title of the calendar entry. e = ics.event.Event(name='Sun time', begin=suntime, duration={'minutes': 10}) c.events.add(e) if args.icsfile: args.icsfile.write(str(c))
def sun_for(day: datetime.datetime, *, latitude: float, longitude: float): observer = astral.Observer(latitude, longitude) return astral.sun.sun(observer, date=day, tzinfo=tf.timezone_at(lat=latitude, lng=longitude))
class screen(Widget): # all of the variables that the ui pulls data from alpha = NumericProperty() otto_info = {'lat': 38.662644, 'long': -121.527298, 'tz': 'US/Pacific'} otto_obs = astral.Observer(latitude=otto_info['lat'], longitude=otto_info['long']) day_length_yesterday_str = StringProperty() day_length_today_str = StringProperty() day_length_tomorrow_str = StringProperty() yesterday_today_delta_str = StringProperty() today_tomorrow_delta_str = StringProperty() date = StringProperty() current_time = StringProperty() day_transition_1 = StringProperty() day_transition_2 = StringProperty() pdt_or_pst_completion_str = StringProperty() year_transition_1 = StringProperty() year_transition_2 = StringProperty() # update all of the numbers that change by-the-minute def update_minute_info(self): # current time, used in many of following calculations rn = datetime.datetime.now(tz=pytz.timezone(self.otto_info['tz'])) self.current_time = rn.strftime('%H:%M') # update alpha brightness according to time of day if rn.time() < datetime.time(6): self.alpha = 0.25 elif rn.time() < datetime.time(20): self.alpha = 0.80 else: self.alpha = 0.25 # TODO: change references from datetime.datetime.today() to rn otto_sun_today = astral.sun.sun(self.otto_obs, rn, tzinfo=self.otto_info['tz']) otto_sun_tomorrow = astral.sun.sun(self.otto_obs, rn + datetime.timedelta(days=1), tzinfo=self.otto_info['tz']) # find next 2 important daily transitions if rn < otto_sun_today['dawn']: # rn before today.dawn #transitions are today.dawn, today.dusk self.day_transition_1 = f'dawn {otto_sun_today["dawn"].strftime("%H:%M")}' self.ids.lbl_daymom_tom_1.color = (1, 1, 0, 0) self.day_transition_2 = f'dusk {otto_sun_today["dusk"].strftime("%H:%M")}' self.ids.lbl_daymom_tom_2.color = (1, 1, 0, 0) elif rn < otto_sun_today['dusk']: # rn before today.dusk: # transitions are today.dusk, tomorrow.dawn self.day_transition_1 = f'dusk {otto_sun_today["dusk"].strftime("%H:%M")}' self.ids.lbl_daymom_tom_1.color = (1, 1, 0, 0) self.day_transition_2 = f'dawn {otto_sun_tomorrow["dawn"].strftime("%H:%M")}' self.ids.lbl_daymom_tom_2.color = (1, 1, 0, self.alpha) else: # transitions are tomorrow.dawn, tomorrow.dusk self.day_transition_1 = f'dawn {otto_sun_tomorrow["dawn"].strftime("%H:%M")}' self.ids.lbl_daymom_tom_1.color = (1, 1, 0, self.alpha) self.day_transition_2 = f'dusk {otto_sun_tomorrow["dusk"].strftime("%H:%M")}' self.ids.lbl_daymom_tom_2.color = (1, 1, 0, self.alpha) # update all of the numbers that change once per day def update_daily_info(self): # current time, used in many of following calculations rn = datetime.datetime.now(tz=pytz.timezone(self.otto_info['tz'])) # get sun times for 3 days otto_sun_yesterday = astral.sun.sun(self.otto_obs, datetime.datetime.today() - datetime.timedelta(days=1), tzinfo=self.otto_info['tz']) otto_sun_today = astral.sun.sun(self.otto_obs, datetime.datetime.today(), tzinfo=self.otto_info['tz']) otto_sun_tomorrow = astral.sun.sun(self.otto_obs, datetime.datetime.today() + datetime.timedelta(days=1), tzinfo=self.otto_info['tz']) # compute day lengths day_length_yesterday = otto_sun_yesterday[ 'sunset'] - otto_sun_yesterday['sunrise'] self.day_length_yesterday_str = self.daylen_tostr(day_length_yesterday) day_length_today = otto_sun_today['sunset'] - otto_sun_today['sunrise'] self.day_length_today_str = self.daylen_tostr(day_length_today) day_length_tomorrow = otto_sun_tomorrow['sunset'] - otto_sun_tomorrow[ 'sunrise'] self.day_length_tomorrow_str = self.daylen_tostr(day_length_tomorrow) # compute how much longer today was vs yesterday, change delta text color self.yesterday_today_delta_str = self.daydelta_tostr( day_length_today - day_length_yesterday) if self.yesterday_today_delta_str[1] == '+': self.ids.yest_delta.color = (0, 1, 0, self.alpha) else: self.ids.yest_delta.color = (1, 0, 0, self.alpha) # compute how much longer tomorrow will be vs today, change delta text color self.today_tomorrow_delta_str = self.daydelta_tostr( day_length_tomorrow - day_length_today) if self.today_tomorrow_delta_str[1] == '+': self.ids.tom_delta.color = (0, 1, 0, self.alpha) else: self.ids.tom_delta.color = (1, 0, 0, self.alpha) # update today's date self.date = rn.strftime('%Y.%m.%d') # compute PST or PDT completion percentage daylight_trans_dates = [ x.date() for x in pytz.timezone('US/Pacific')._utc_transition_times if x.year >= rn.year - 1 and x.year <= rn.year + 1 ] # has daylight times last year to next year if rn.date( ) < daylight_trans_dates[2]: # before this year's spring forward) # useful dates are last year's fall back and this year's spring forward. currently PST pst_duration_days = daylight_trans_dates[2] - daylight_trans_dates[ 1] pst_completed_days = rn.date() - daylight_trans_dates[1] self.pdt_or_pst_completion_str = f'PST is {pst_completed_days/pst_duration_days*100:.2f}% done.' elif rn.date( ) < daylight_trans_dates[3]: # between [spring forward and fall back) # useful dates: this year's spring forward, fall back. currently PDT :) pdt_duration_days = daylight_trans_dates[3] - daylight_trans_dates[ 2] pdt_completed_days = rn.date() - daylight_trans_dates[2] self.pdt_or_pst_completion_str = f'PDT is {pdt_completed_days/pdt_duration_days*100:.2f}% done.' else: # you're after this year's fall back] # useful dates: this year's fall back, next year's spring forward. currently PST pst_duration_days = daylight_trans_dates[4] - daylight_trans_dates[ 3] pst_completed_days = rn.date() - daylight_trans_dates[3] self.pdt_or_pst_completion_str = f'PST is {pst_completed_days/pst_duration_days*100:.2f}% done.' # find next 2 important yearly transitions. include time changes, equinoxes, solstices year_transitions = [['spring forward', daylight_trans_dates[2]], ['fall back', daylight_trans_dates[3]]] year_transitions.append([ 'spring equinox', ephem.next_spring_equinox(str(rn.year)).datetime().date() ]) year_transitions.append([ 'summer solstice', ephem.next_summer_solstice(str(rn.year)).datetime().date() ]) year_transitions.append([ 'fall equinox', ephem.next_fall_equinox(str(rn.year)).datetime().date() ]) year_transitions.append([ 'winter solstice', ephem.next_winter_solstice(str(rn.year)).datetime().date() ]) year_transitions.append(['spring forward', daylight_trans_dates[4]]) year_transitions.append([ 'spring equinox', ephem.next_spring_equinox(str(rn.year + 1)).datetime().date() ]) # sort the transitions. (are these astronomical events always guaranteed to be in the same order?) year_transitions.sort(key=lambda x: x[1]) year_transitions = [x for x in year_transitions if rn.date() <= x[1]] self.year_transition_1 = f'{year_transitions[0][0]} {year_transitions[0][1].strftime("%Y.%m.%d")} ' \ f'Δ{(year_transitions[0][1] - rn.date()).days}d' self.year_transition_2 = f'{year_transitions[1][0]} {year_transitions[1][1].strftime("%Y.%m.%d")} ' \ f'Δ{(year_transitions[1][1] - rn.date()).days}d' def daylen_tostr(self, td): rtn = f'{td.seconds // 3600:02}h ' \ f'{(td.seconds % 3600) // 60:02}m ' \ f'{(td.seconds % 60):02}s' return rtn def daydelta_tostr(self, td): rtn = 'Δ' if td < datetime.timedelta(): td = -td rtn += '-' else: rtn += '+' rtn += f'{(td.seconds % 3600) // 60:02}m:' \ f'{(td.seconds % 60):02}s' return rtn
def fft_shading_test_process(time, lat, lon, data, shad_freq_lower=None, shad_freq_upper=None, ratio_thresh=None, time_interval=None): """ Processing function to do the FFT calculations/thresholding Parameters ---------- time : datetime Center time of calculation used for calculating sunrise/sunset lat : float Latitude used for calculating sunrise/sunset lon : float Longitude used for calculating sunrise/sunset data : list Data for run through fft processing shad_freq_lower : list Lower limits of freqencies to look for shading issues shad_freq_upper : list Upper limits of freqencies to look for shading issues ratio_thresh : list Thresholds to apply, corresponding to frequencies chosen time_interval : float Time interval of data Returns ------- shading : int Binary to indicate shading problem (1) or not (0) """ # Get sunrise/sunset that are on same days # This is used to help in the processing and easily exclude # nighttime data from processing if ASTRAL: astral.solar_depression = 0 obs = astral.Observer(latitude=float(lat), longitude=float(lon)) s = sun(obs, pd.Timestamp(time)) else: a = astral.Astral() a.solar_depression = 0 s = a.sun_utc(pd.Timestamp(time), float(lat), float(lon)) sr = s['sunrise'].replace(tzinfo=None) ss = s['sunset'].replace(tzinfo=None) delta = ss.date() - sr.date() if delta > datetime.timedelta(days=0): if ASTRAL: s = sun(obs, pd.Timestamp(time) - datetime.timedelta(days=1)) else: s = a.sun_utc(pd.Timestamp(time), float(lat), float(lon)) ss = s['sunset'].replace(tzinfo=None) # Set if night or not shading = 0 night = False if sr < ss: if (pd.Timestamp(time) < sr) or (pd.Timestamp(time) > ss): night = True if sr > ss: if (pd.Timestamp(time) < sr) and (pd.Timestamp(time) > ss): night = True # Return shading of 0 if no valid data or it's night if len(data) == 0 or night is True: return shading # FFT Algorithm fftv = abs(rfft(data)) freq = rfftfreq(fftv.size, d=time_interval) # Get FFT data under threshold idx = (fftv < 1.) index = np.where(idx) fftv = fftv[index] freq = freq[index] # Return if FFT is empty if len(fftv) == 0: return 0 # Commented out as it seems to work better without smoothing # fftv=pd.DataFrame(data=fftv).rolling(min_periods=3,window=3,center=True).mean().values.flatten() ratio = [] # Calculates the ratio (size) of the peaks in the FFT to the surrounding # data wind = 3 # Run through each frequency to look for peaks # Calculate threshold of peak value to surrounding values for i in range(len(shad_freq_lower)): idx = np.logical_and(freq > shad_freq_lower[i], freq < shad_freq_upper[i]) index = np.where(idx) if len(index[0]) == 0: continue peak = max(fftv[index]) index = index[0] sind = index[0] - wind if sind < 0: sind = 0 eind = index[-1] + wind if eind > len(fftv): eind = len(fftv) if len(range(sind, index[0])) == 0 or len(range(index[-1], eind)) == 0: ratio.append(0.0) else: # Calculates to the left/right of each peak peak_l = max(fftv[range(sind, index[0])]) peak_r = max(fftv[range(index[-1], eind)]) ratio.append(peak / np.mean([peak_l, peak_r])) # Checks ratios against thresholds for each freq range shading = 0 if len(ratio) > 0: pass1 = False pass2 = False if ratio[0] > ratio_thresh[0]: pass1 = True if len(ratio) > 1: if ratio[1] > ratio_thresh[1]: pass2 = True else: pass2 = True if pass1 and pass2: shading = 1 return shading