def __init__(self, devices): self.__devices = devices self.__stir_state = False self.__current = Timer("stir") self.__period = timedelta(seconds=3600) self.__duration = timedelta(seconds=120) self.__city = geocoder.lookup(StirMode.LOCATION, geocoder.database())
def geolocate(address, try_all=True): try: # see https://astral.readthedocs.io/en/latest/#cities a = lookup(address, database()) return a.latitude, a.longitude except: pass # use online geocoder location_data = geocoder.geonames(address, method='details', key='jarbas') if not location_data.ok: location_data = geocoder.geocodefarm(address) if not location_data.ok: location_data = geocoder.osm(address) if try_all: # more are just making it slow if not location_data.ok: location_data = geocoder.google(address) if not location_data.ok: location_data = geocoder.arcgis(address) if not location_data.ok: location_data = geocoder.bing(address) if not location_data.ok: location_data = geocoder.canadapost(address) if not location_data.ok: location_data = geocoder.yandex(address) if not location_data.ok: location_data = geocoder.tgos(address) if location_data.ok: location_data = location_data.json lat = location_data.get("lat") lon = location_data.get("lng") return lat, lon raise ValueError
def test_Wellington(): wellington = lookup("Wellington", database()) dt = datetime.date(2020, 2, 11) tz = pytz.timezone(wellington.timezone) s = sun(wellington.observer, dt, tzinfo=tz) assert datetime_almost_equal( s["sunrise"], tz.localize(datetime.datetime(2020, 2, 11, 6, 38, 42)))
def __init__(self, city_name=default_city_name): if VERSION == 2: self._city = lookup("Amsterdam", database()) self._sun = self.sun(datetime.now()) else: self._a = Astral() self._a.solar_depression = 'civil' self._city = self._a[city_name] self._timezone = pytz.timezone(self._city.timezone)
def sun_moon_time(city_name, time_zone): """Calculate the progress through the current sun/moon period (i.e day or night) from the last sunrise or sunset, given a datetime object 't'.""" city = lookup(city_name, database()) # Datetime objects for yesterday, today, tomorrow utc = pytz.utc utc_dt = datetime.now(tz=utc) local_dt = utc_dt.astimezone(pytz.timezone(time_zone)) today = local_dt.date() yesterday = today - timedelta(1) tomorrow = today + timedelta(1) # DEBUG breakpoint TEST! # breakpoint() logger.info( ' The current date/time is %s in your local TimeZone/City of %s', local_dt, time_zone) # logger.debug(local_dt) # Sun objects for yesterday, today, tomorrow sun_yesterday = sun(city.observer, date=yesterday) sun_today = sun(city.observer, date=today) sun_tomorrow = sun(city.observer, date=tomorrow) # Work out sunset yesterday, sunrise/sunset today, and sunrise tomorrow sunset_yesterday = sun_yesterday["sunset"] sunrise_today = sun_today["sunrise"] sunset_today = sun_today["sunset"] sunrise_tomorrow = sun_tomorrow["sunrise"] # Work out lengths of day or night period and progress through period if sunrise_today < local_dt < sunset_today: day = True period = sunset_today - sunrise_today # mid = sunrise_today + (period / 2) progress = local_dt - sunrise_today elif local_dt > sunset_today: day = False period = sunrise_tomorrow - sunset_today # mid = sunset_today + (period / 2) progress = local_dt - sunset_today else: day = False period = sunrise_today - sunset_yesterday # mid = sunset_yesterday + (period / 2) progress = local_dt - sunset_yesterday # Convert time deltas to seconds progress = progress.total_seconds() period = period.total_seconds() return (progress, period, day, local_dt)
def length_day(series,lon,lat): db = database() lon = deg_to_dms(lon, 'lon') # 经度 lat = deg_to_dms(lat, 'lat') add_locations("Somewhere,Secret Location,UTC," + lat + ',' + lon, db) s = sun(lookup("Somewhere", db).observer, date=series['date']) print(series['date']) len_day = s['sunset']-s['sunrise'] return len_day.seconds/3600.0
def __init__(self, config_file_path=None): # catch SIGINT, SIGQUIT and SIGTERM self.__quit_signal = threading.Event() signal.signal(signal.SIGINT, self.__quit) signal.signal(signal.SIGQUIT, self.__quit) signal.signal(signal.SIGTERM, self.__quit) # catch SIGHUP and reload configuration signal.signal(signal.SIGHUP, self.__reload) # load config if config_file_path is None: self.__config_file_path = DEFAULT_CONFIG_FILE else: self.__config_file_path = config_file_path self.__load_settings() # this is the queue that holds the frames to display self.__frame_queue = queue.Queue(maxsize=1) # animation controller # gets initialized in mainloop method self.__animation_controller = AnimationController( self.config, self.frame_queue) # the animation scheduler self.__animation_scheduler = self.__create_scheduler() self.__schedule_lock = Lock() # the nighttime scheduler self.__location = lookup(tzlocal.get_localzone_name().split("/")[1], database()) self.__nighttime_scheduler = BackgroundScheduler() self.__sunrise_job = self.__nighttime_scheduler.add_job( func=self.apply_brightness) self.__sunset_job = self.__nighttime_scheduler.add_job( func=self.apply_brightness) self.__nighttime_scheduler.add_job(func=self.__calculate_nighttimes, trigger=CronTrigger(hour="0,12", minute=0, second=0)) self.__calculate_nighttimes() self.apply_brightness() self.__nighttime_scheduler.start() # create the display object self.__initialize_display() # server interfaces self.__http_server = None self.__rest_server = None self.__tpm2_net_server = None # this signal is set by the reload method self.__reload_signal = EventWithUnsetSignal()
def __init__(self, city=None): """ Initialize Sun class :param city: City name :type city: str """ from astral.geocoder import database, lookup if city is None: city = 'Brussels' if isinstance(city, str): city = lookup(city, database()) self._city = city
def make(self): self.info = sun(lookup(self.look_up, database()).observer, date=datetime.date(self.with_date.year, self.with_date.month, self.with_date.day)) if type(self.info) != dict: return for val in self.info: self.info[val] = { 'utc': self.info[val], 'local': self.info[val].astimezone(tz.gettz(self.time_zone)) } self.__create_wallpaper_time_slots() return self.info
def sun_moon_time(dt, city_name, time_zone): """Calculate the progress through the current sun/moon period (i.e day or night) from the last sunrise or sunset, given a datetime object 't'.""" city = lookup(city_name, database()) # Datetime objects for yesterday, today, tomorrow today = dt.date() dt = pytz.timezone(time_zone).localize(dt) yesterday = today - timedelta(1) tomorrow = today + timedelta(1) # Sun objects for yesterfay, today, tomorrow sun_yesterday = sun(city.observer, date=yesterday) sun_today = sun(city.observer, date=today) sun_tomorrow = sun(city.observer, date=tomorrow) # Work out sunset yesterday, sunrise/sunset today, and sunrise tomorrow sunset_yesterday = sun_yesterday["sunset"] sunrise_today = sun_today["sunrise"] sunset_today = sun_today["sunset"] sunrise_tomorrow = sun_tomorrow["sunrise"] # Work out lengths of day or night period and progress through period if sunrise_today < dt < sunset_today: day = True period = sunset_today - sunrise_today mid = sunrise_today + (period / 2) progress = dt - sunrise_today elif dt > sunset_today: day = False period = sunrise_tomorrow - sunset_today mid = sunset_today + (period / 2) progress = dt - sunset_today else: day = False period = sunrise_today - sunset_yesterday mid = sunset_yesterday + (period / 2) progress = dt - sunset_yesterday # Convert time deltas to seconds progress = progress.total_seconds() period = period.total_seconds() return (progress, period, day)
def get_max_theoretical_sun_hours(city, max_real_sun_hours): city_data = lookup(city, database()) start = f"{YEAR_MAX_SUN_HOURS}-01-01" end = f"{YEAR_MAX_SUN_HOURS}-12-31" dates = pd.date_range(start=start, end=end) daylight_hours = get_daylight_hours(city_data.observer, dates) grouped_daylight_hours = daylight_hours.groupby( [daylight_hours.index.month, daylight_hours.index.day]).max() grouped_daylight_hours = pd.Series(grouped_daylight_hours['daylight_h']) _max_real_sun_hours = pd.Series(max_real_sun_hours) delta_sun_and_daylight = grouped_daylight_hours - _max_real_sun_hours min_delta = delta_sun_and_daylight.nsmallest(10).mean() daylight_hours['sunhours'] = daylight_hours['daylight_h'] - min_delta return daylight_hours
def send(): if request.method=='POST': data=request.json startdate=datetime.strptime(data['date'],'%Y-%m-%d') enddate=datetime.strptime(data['date1'],'%Y-%m-%d') cityinfo=data['city'] city=lookup(cityinfo, database()) day = timedelta(days=1) table2=[] while startdate <= enddate: suns=sun(city.observer, date=startdate, tzinfo=pytz.timezone(city.timezone)) dawn=suns['dawn'].strftime("%H:%M:%S") sunrise=suns['sunrise'].strftime("%H:%M:%S") sunset=suns['sunset'].strftime("%H:%M:%S") dusk=suns['dusk'].strftime("%H:%M:%S") noon=suns['noon'].strftime("%H:%M:%S") table2.append({'date':startdate.strftime('%Y-%m-%d'),'dawn':dawn,'sunrise':sunrise,'sunset':sunset,'dusk':dusk,'noon':noon}) startdate=startdate+day table1={'city':city.name,'region':city.region,'timezone':city.timezone,'long':round(city.longitude,2),'lat':round(city.latitude,2)} return json.dumps({'table1':table1,'table2':table2})
def __init__(self): try: config = self._load_config() except Exception as ex: print(f'Using default config: {ex}') config = self.default_config self.config = config if isinstance(config['location'], str): location = lookup(config['location'], database()) position = {"lat": location.latitude, "lon": location.longitude} else: position = config['location'] self.position = position # Date and time formats self.time_format = self.time_formats[config['time']]\ if config['time'] in self.time_formats else self.time_formats['24h'] self.time_format_tz = self.time_format + ' %Z' self.date_format = '%b %d, %Y'
def geolocate(self, address, try_all=True): if address in self.geocache: return self.geocache[address] try: # should be installed from default skills from astral.geocoder import database, lookup # see https://astral.readthedocs.io/en/latest/#cities a = lookup(address, database()) self.geocache[address] = (a.latitude, a.longitude) return a.latitude, a.longitude except: pass # use online geocoder location_data = geocoder.osm(address) if not location_data.ok: location_data = geocoder.geocodefarm(address) if try_all: # more are just making it slow if not location_data.ok: location_data = geocoder.google(address) if not location_data.ok: location_data = geocoder.arcgis(address) if not location_data.ok: location_data = geocoder.bing(address) if not location_data.ok: location_data = geocoder.canadapost(address) if not location_data.ok: location_data = geocoder.yandex(address) if not location_data.ok: location_data = geocoder.tgos(address) if location_data.ok: location_data = location_data.json lat = location_data.get("lat") lon = location_data.get("lng") self.geocache[address] = (lat, lon) return lat, lon raise ValueError
import os.path import operator from dateutil.relativedelta import relativedelta from numpy import asarray from astral import geocoder from astral import location import astral import sys import os import subprocess import glob import time from PIL import Image #getting the list of all US cities in the astral database db = geocoder.database() locations = geocoder.all_locations(db) locList = [] usaLocList = {} for location in locations: locList.append(location) if location.region == 'USA': usaLocList[location.name] = location ##################################### #setup GLOBALs time and sun calculations utc = pytz.UTC ##################################### # setup GLOBALs design: tower hight in meters, tracker dimensions DistanceToSun = 10200 # far away so all rays are parallel
def getSun(city_name): city = lookup(city_name, database()) return sun(city.observer, date=datetime.date.today())
def run(): defaults = { 'log': "info" } # Parse any config file specification. We make this parser with add_help=False so # that it doesn't parse -h and print help. conf_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, add_help=False ) conf_parser.add_argument("--config", help="Specify config file", metavar='FILE') args, remaining_argv = conf_parser.parse_known_args() # Read configuration file and add it to the defaults hash. if args.config: config = ConfigParser() config.read(args.config) if "Defaults" in config: defaults.update(dict(config.items("Defaults"))) else: sys.exit("Bad config file, missing Defaults section") # Parse rest of arguments parser = argparse.ArgumentParser( description=__doc__, parents=[conf_parser], ) parser.set_defaults(**defaults) parser.add_argument("--gw-station-id", help="GoodWe station ID", metavar='ID') parser.add_argument("--gw-account", help="GoodWe account", metavar='ACCOUNT') parser.add_argument("--gw-password", help="GoodWe password", metavar='PASSWORD') parser.add_argument("--pvo-system-id", help="PVOutput system ID", metavar='ID') parser.add_argument("--pvo-api-key", help="PVOutput API key", metavar='KEY') parser.add_argument("--pvo-interval", help="PVOutput interval in minutes", type=int, choices=[5, 10, 15]) parser.add_argument("--darksky-api-key", help="Dark Sky Weather API key") parser.add_argument("--openweather-api-key", help="Open Weather API key") parser.add_argument("--netatmo-username", help="Netatmo username") parser.add_argument("--netatmo-password", help="Netatmo password") parser.add_argument("--netatmo-client-id", help="Netatmo OAuth client id") parser.add_argument("--netatmo-client-secret", help="Netatmo OAuth client secret") parser.add_argument("--netatmo-device-id", help="Netatmo device id") parser.add_argument("--log", help="Set log level (default info)", choices=['debug', 'info', 'warning', 'critical']) parser.add_argument("--date", help="Copy all readings (max 14/90 days ago)", metavar='YYYY-MM-DD') parser.add_argument("--pv-voltage", help="Send pv voltage instead of grid voltage", action='store_true') parser.add_argument("--skip-offline", help="Skip uploads when inverter is offline", action='store_true') parser.add_argument("--city", help="Sets timezone and skip uploads from dusk till dawn") parser.add_argument('--csv', help="Append readings to a Excel compatible CSV file, DATE in the name will be replaced by the current date") parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) args = parser.parse_args() # Configure the logging numeric_level = getattr(logging, args.log.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: %s' % loglevel) logging.basicConfig(format='%(levelname)-8s %(message)s', level=numeric_level) logging.debug("gw2pvo version " + __version__) if isinstance(args.skip_offline, str): args.skip_offline = args.skip_offline.lower() in ['true', 'yes', 'on', '1'] if args.gw_station_id is None or args.gw_account is None or args.gw_password is None: sys.exit("Missing --gw-station-id, --gw-account and/or --gw-password") if args.city: city = Location(lookup(args.city, database())) os.environ['TZ'] = city.timezone time.tzset() else: city = None logging.debug("Timezone {}".format(datetime.now().astimezone().tzinfo)) # Check if we want to copy old data if args.date: try: copy(args) except KeyboardInterrupt: sys.exit(1) except Exception as exp: logging.error(exp) sys.exit() startTime = datetime.now() while True: try: run_once(args, city) except KeyboardInterrupt: sys.exit(1) except Exception as exp: logging.error(exp) if args.pvo_interval is None: break interval = args.pvo_interval * 60 time.sleep(interval - (datetime.now() - startTime).seconds % interval)
def main(): time_now = datetime.datetime.now() timezone_delta = datetime.timedelta(hours=-13) honolulu_utc_delta = datetime.timedelta(hours=-10) one_day_delta = datetime.timedelta(days=1) # Time now on Haleakala, Hawaii haleakala_time = time_now + timezone_delta haleakala_midnight_time = haleakala_time - datetime.timedelta( hours=haleakala_time.hour, minutes=haleakala_time.minute, seconds=haleakala_time.second, microseconds=haleakala_time.microsecond) fig, ax = plt.subplots(1, 1, figsize=(15, 5)) numb_of_days = 14 midnights = np.arange(0, numb_of_days + 1, 1) ax.set_xlim(0, numb_of_days) ax.set_ylim(0, 1) ax.set_yticks([]) ax.set_xticks(midnights) date_labels = [ (haleakala_midnight_time + i * one_day_delta).strftime('%d.%m') for i in range(numb_of_days + 1) ] ax.set_xticklabels(date_labels) plot_objects(ax, haleakala_midnight_time, numb_of_days) city = lookup("Honolulu", database()) time_positions, time_labels = [], [] for day_number in range(numb_of_days + 1): s = sun(city.observer, date=haleakala_midnight_time + day_number * one_day_delta, tzinfo=city.timezone) time_dawn = s['dawn'] time_sunset = s['sunset'] dawn_hour = int(time_dawn.strftime('%H')) dawn_minute = int(time_dawn.strftime('%M')) dawn_position = (dawn_hour * 60 + dawn_minute) / 1440 time_positions.append(dawn_position + day_number) time_labels.append(time_dawn.strftime('%H:%M')) sunset_hour = int(time_sunset.strftime('%H')) sunset_minute = int(time_sunset.strftime('%M')) sunset_position = (sunset_hour * 60 + sunset_minute) / 1440 time_positions.append(sunset_position + day_number) time_labels.append(time_sunset.strftime('%H:%M')) ax.axvspan(day_number + dawn_position, day_number + sunset_position, alpha=.5, hatch='//', edgecolor='k') ax.vlines(day_number + dawn_position, ymin=0, ymax=1, color='k', linewidth=.5, linestyle='dashed') ax.vlines(day_number + sunset_position, ymin=0, ymax=1, color='k', linewidth=.5, linestyle='dashed') ax2 = ax.twiny() ax2.set_xlim(0, numb_of_days) ax2.set_xticks(time_positions[:-2]) ax2.set_xticklabels(time_labels[:-2]) ax2.xaxis.set_ticks_position('bottom') ax.vlines(midnights, ymin=0, ymax=1, color='k', linewidth=.5, linestyle='dotted') ax.xaxis.set_ticks_position('top') plt.tight_layout() plt.savefig('ephemeris.pdf') plt.show()
def __init__(self): self.sanDiego = lookup("San Diego", database()) self.tz_sd = pytz.timezone(str(self.sanDiego.tzinfo))
def main(): # Create api credentials credentials = None if os.path.exists('credentials.dat'): with open('credentials.dat', 'rb') as credentials_dat: credentials = pickle.load(credentials_dat) if not credentials: flow = Flow.from_client_secrets_file( 'client_id.json', scopes=['https://www.googleapis.com/auth/calendar.readonly'], redirect_uri=REDIRECT_URI) code = request.args.get('code') if not code: auth_url, _ = flow.authorization_url(prompt='consent') return redirect(auth_url) flow.fetch_token(code=code) credentials = flow.credentials with open('credentials.dat', 'wb') as credentials_dat: pickle.dump(credentials, credentials_dat) if credentials and credentials.expired: credentials.refresh(Request()) bigfont = ImageFont.truetype("fonts/Roboto.ttf", 26, encoding="unic") font = ImageFont.truetype("fonts/Roboto.ttf", 20, encoding="unic") smallfont = ImageFont.truetype("fonts/Roboto.ttf", 18, encoding="unic") smallerfont = ImageFont.truetype("fonts/Roboto.ttf", 12, encoding="unic") boldfont = ImageFont.truetype("fonts/RobotoBold.ttf", 18, encoding="unic") # Get forecast r = requests.get( 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/{}?res=3hourly&key={}' .format(MO_LOCATION_ID, MO_API_KEY)) data = r.json() # Convert forecast to something readable hourly_predictions = [] for day in data["SiteRep"]['DV']['Location']['Period']: date = day['value'][:-1] predictions = day['Rep'] for prediction in predictions: prediction['date'] = date prediction['time'] = str(int(int(prediction['$']) / 60)) + ':00' prediction['datetime'] = date + ' ' + str( int(int(prediction['$']) / 60)) + ':00' hourly_predictions.append(prediction) hourly_updated_at = arrow.get(data["SiteRep"]['DV']['dataDate']) r = requests.get( 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/{}?res=daily&key={}' .format(MO_LOCATION_ID, MO_API_KEY)) data = r.json() # Convert forecast to something readable daily_predictions = [] for day in data["SiteRep"]['DV']['Location']['Period']: date = day['value'][:-1] daypred = day['Rep'][0] nightpred = day['Rep'][1] daily_predictions.append({ "date": date, "Dm": daypred['Dm'], "Nm": nightpred['Nm'], "PPd": daypred['PPd'], "PPn": nightpred['PPn'], "W": daypred['W'], "Dd": daypred['D'], "Dn": nightpred['D'], "Gn": daypred['Gn'], "Gm": nightpred['Gm'] }) daily_updated_at = arrow.get(data["SiteRep"]['DV']['dataDate']) # Get todays sunrise and sunset now = arrow.now(TIMEZONE) location = lookup(ASTRAL_LOCATION, database()) sun = sunny(location.observer, date=now) sunrise = sun['sunrise'] sunset = sun['sunset'] day_len = sunset - sunrise # Get yesterdays sunrise and sunset d_yest = now.shift(days=-1) sun_yest = sunny(location.observer, date=d_yest) sunrise_yest = arrow.get(sun_yest['sunrise']) sunset_yest = arrow.get(sun_yest['sunset']) day_len_yest = sunset_yest - sunrise_yest day_len_diff = time_diff(day_len, day_len_yest) sunrise_diff = time_diff(sunrise, sunrise_yest.shift(days=1)) sunset_diff = time_diff(sunset, sunset_yest.shift(days=1)) # Get upcoming calendar events calendar_sdk = build('calendar', 'v3', credentials=credentials) calendar_list = calendar_sdk.calendarList().list().execute() calendar_ids = [ calendar_list_entry['id'] for calendar_list_entry in calendar_list['items'] ] today = arrow.now(TIMEZONE) today_morning = today.strftime('%Y-%m-%dT00:00:00Z') tomorrow = today.shift(days=1) events = [] for calendar_id in calendar_ids: events_page = calendar_sdk.events().list( calendarId=calendar_id, timeMin=today_morning, maxResults=10, singleEvents=True, orderBy="startTime", ).execute() events += events_page['items'] def get_key(event): if 'dateTime' in event['start']: return arrow.get(event['start']['dateTime']) else: return arrow.get(event['start']['date']) events.sort(key=get_key) def calendar(draw, start_x, start_y, end_y): x = start_x y = start_y item_spacing = 25 extra_day_spacing = 5 current_date = None for event in events: if y >= end_y: break summary = event['summary'] if 'organizer' in event and 'displayName' in event['organizer']: calendar = event['organizer']['displayName'] if 'dateTime' in event['start']: start_time = arrow.get(event['start']['dateTime']) end_time = arrow.get(event['end']['dateTime']) diff = abs(start_time - end_time) time_text = start_time.strftime('%H:%M') + ' ' + str( diff.seconds // 3600) + ' hours' else: start_time = arrow.get(event['start']['date']) time_text = 'All day' if current_date != start_time.strftime('%Y/%m/%d'): if y + item_spacing + extra_day_spacing >= 750: break y += extra_day_spacing if start_time.strftime('%Y/%m/%d') == today.strftime( '%Y/%m/%d'): text = 'Today' elif start_time.strftime('%Y/%m/%d') == tomorrow.strftime( '%Y/%m/%d'): text = 'Tomorrow' else: text = start_time.humanize().capitalize( ) + ' on ' + start_time.format( 'dddd {} Do {} MMMM').format('the', 'of') draw.text((x, y), text, (0, 0, 0), boldfont) current_date = start_time.strftime('%Y/%m/%d') y += item_spacing text = time_text draw.text((x, y), text, (0, 0, 0), smallfont) text = summary if len(text) > 60: text = text[:57] + '...' draw.text((x + 125, y), text, (0, 0, 0), smallfont) y += item_spacing def landscape(): # Make blank image image_pixels = [(255, 255, 255) for i in range(800 * 600)] image = Image.new("RGBA", (800, 600)) image.putdata(image_pixels) draw = ImageDraw.Draw(image) # Big date title text = now.format('dddd {} Do {} MMMM YYYY').format('the', 'of') w, h = bigfont.getsize(text) center_offset = (800 - w) / 2 draw.text((center_offset, 5), text, (0, 0, 0), bigfont) # Render sunrise icon and todays sunrise time icon = Image.open('icons/sunrise.png') image.paste(icon, box=(10, 20), mask=icon) text = sunrise.strftime('%H:%M') w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((10 + center_offset, 110), text, (0, 0, 0), bigfont) # Render sunrise diff text = '(' + sunrise_diff + ')' w, h = smallfont.getsize(text) center_offset = (100 - w) / 2 draw.text((10 + center_offset, 145), text, (0, 0, 0), smallfont) start_offset = 112 start_height = 20 column_width = 100 spacing = 8 for index, prediction in enumerate(hourly_predictions[1:6]): left_offset = (spacing * (index + 1)) + ( index * (column_width + spacing)) + start_offset # Draw weather icon icon = Image.open('icons/' + prediction["W"] + '.png') image.paste(icon, box=(left_offset, start_height), mask=icon) # Write datetime text = prediction["time"] w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, start_height + 90), text, (0, 0, 0), bigfont) # Write temperature icon = Image.open('icons/small/thermometer.png') image.paste(icon, box=(left_offset, start_height + 120), mask=icon) text = prediction["F"] + '°C' w, h = font.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, start_height + 120), text, (0, 0, 0), font) # Write rain chance icon = Image.open('icons/small/rain.png') image.paste(icon, box=(left_offset, start_height + 145), mask=icon) text = prediction["Pp"] + '%' w, h = font.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, start_height + 145), text, (0, 0, 0), font) # Write wind icon = Image.open('icons/small/deg-' + prediction['D'] + '.png') image.paste(icon, box=(left_offset, start_height + 175), mask=icon) text = str(int(1.609344 * float(prediction["S"]))) + "kph" w, h = smallfont.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, start_height + 175), text, (0, 0, 0), smallfont) # Render sunset icon and todays sunset time icon = Image.open('icons/sunset.png') image.paste(icon, box=(680, 20), mask=icon) text = sunset.strftime('%H:%M') w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((680 + center_offset, 110), text, (0, 0, 0), bigfont) # Render sunset diff text = '(' + sunset_diff + ')' w, h = smallfont.getsize(text) center_offset = (100 - w) / 2 draw.text((680 + center_offset, 145), text, (0, 0, 0), smallfont) # Hourly updated text = 'Updated ' + hourly_updated_at.format('ddd h a') draw.text((5, 215), text, (0, 0, 0), smallerfont) # Horizontal Line draw.line((0, 230, 800, 230), fill=255) # 4 day forecast start_height = 230 spacing = 10 row_height = 70 for index, prediction in enumerate(daily_predictions[1:6]): top_offset = (spacing * (index + 1)) + ( index * (row_height + spacing)) + start_height # Write datetime text = arrow.get( prediction["date"]).format('dddd {} Do {} MMMM YYYY').format( 'the', 'of') draw.text((5, top_offset), text, (0, 0, 0), smallfont) # Draw weather icon icon = Image.open('icons/med/' + prediction["W"] + '.png') image.paste(icon, box=(0, top_offset + 25), mask=icon) # Write day draw.text((70, top_offset + 25), "Day", (0, 0, 0), smallfont) # Write night draw.text((70, top_offset + 50), "Night", (0, 0, 0), smallfont) # Write max temperature icon = Image.open('icons/small/thermometer.png') image.paste(icon, box=(120, top_offset + 25), mask=icon) text = prediction["Dm"] + '°C' draw.text((150, top_offset + 25), text, (0, 0, 0), smallfont) # Write min temperature icon = Image.open('icons/small/thermometer.png') image.paste(icon, box=(120, top_offset + 50), mask=icon) text = prediction["Nm"] + '°C' draw.text((150, top_offset + 50), text, (0, 0, 0), smallfont) # Write day rain chance icon = Image.open('icons/small/rain.png') image.paste(icon, box=(200, top_offset + 25), mask=icon) text = prediction["PPd"] + '%' draw.text((230, top_offset + 25), text, (0, 0, 0), smallfont) # Write night rain chance icon = Image.open('icons/small/rain.png') image.paste(icon, box=(200, top_offset + 50), mask=icon) text = prediction["PPn"] + '%' draw.text((230, top_offset + 50), text, (0, 0, 0), smallfont) # Write day wind icon = Image.open('icons/small/deg-' + prediction['Dd'] + '.png') image.paste(icon, box=(280, top_offset + 25), mask=icon) text = str(int(1.609344 * float(prediction["Gn"]))) + "kph" draw.text((310, top_offset + 25), text, (0, 0, 0), smallfont) # Write night wind icon = Image.open('icons/small/deg-' + prediction['Dn'] + '.png') image.paste(icon, box=(280, top_offset + 50), mask=icon) text = str(int(1.609344 * float(prediction["Gm"]))) + "kph" draw.text((310, top_offset + 50), text, (0, 0, 0), smallfont) # Vertical Line draw.line((400, 230, 400, 600), fill=255) # Calendar calendar(draw, 420, 235, 550) # Daily updated text = 'Updated ' + daily_updated_at.format('ddd h a') draw.text((5, 585), text, (0, 0, 0), smallerfont) # Calendar and General checked at text = 'Updated ' + now.format('ddd h a') draw.text((420, 585), text, (0, 0, 0), smallerfont) image = image.rotate(-90, expand=True) image.save(IMAGE_NAME, "PNG") def portrait(): # Make blank image image_pixels = [(255, 255, 255) for i in range(600 * 800)] image = Image.new("RGBA", (600, 800)) image.putdata(image_pixels) draw = ImageDraw.Draw(image) for index, prediction in enumerate(hourly_predictions[1:6]): left_offset = (10 * (index + 1)) + (index * 110) # Draw weather icon icon = Image.open('icons/' + prediction["W"] + '.png') image.paste(icon, box=(left_offset, 0), mask=icon) # Write datetime text = prediction["time"] w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, 90), text, (0, 0, 0), bigfont) # Write temperature icon = Image.open('icons/small/thermometer.png') image.paste(icon, box=(left_offset, 120), mask=icon) text = prediction["F"] + '°C' w, h = font.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, 120), text, (0, 0, 0), font) # Write rain chance icon = Image.open('icons/small/rain.png') image.paste(icon, box=(left_offset, 145), mask=icon) text = prediction["Pp"] + '%' w, h = font.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, 145), text, (0, 0, 0), font) # Write wind icon = Image.open('icons/small/deg-' + prediction['D'] + '.png') image.paste(icon, box=(left_offset, 175), mask=icon) text = str(int(1.609344 * float(prediction["S"]))) + "kph" w, h = smallfont.getsize(text) center_offset = (100 - w) / 2 draw.text((left_offset + center_offset, 175), text, (0, 0, 0), smallfont) # Render sunrise icon and todays sunrise time icon = Image.open('icons/sunrise.png') image.paste(icon, box=(130, 200), mask=icon) text = sunrise.strftime('%H:%M') w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((130 + center_offset, 290), text, (0, 0, 0), bigfont) # Render sun icon, day length and day length diff from yesterday icon = Image.open('icons/1.png') image.paste(icon, box=(250, 200), mask=icon) text = ':'.join(str(day_len).split(':')[:2]) w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((250 + center_offset, 290), text, (0, 0, 0), bigfont) text = '(' + day_len_diff + ')' w, h = smallfont.getsize(text) center_offset = (100 - w) / 2 draw.text((250 + center_offset, 320), text, (0, 0, 0), smallfont) # Render sunset icon and todays sunset time icon = Image.open('icons/sunset.png') image.paste(icon, box=(370, 200), mask=icon) text = sunset.strftime('%H:%M') w, h = bigfont.getsize(text) center_offset = (100 - w) / 2 draw.text((370 + center_offset, 290), text, (0, 0, 0), bigfont) # Write checked time and updated time text = 'Checked at ' + now.format( 'ddd h a') + ' and last updated at ' + hourly_updated_at.format( 'ddd h a') draw.text((10, 775), text, (0, 0, 0), smallfont) draw.line((0, 345, 600, 345), fill=255) text = now.format('dddd {} Do {} MMMM YYYY').format('the', 'of') w, h = bigfont.getsize(text) center_offset = (600 - w) / 2 draw.text((center_offset, 350), text, (0, 0, 0), bigfont) calendar(draw, 10, 380, 750) image.save(IMAGE_NAME, "PNG") landscape() if request.args.get('landscape') is not None else portrait() return send_file(IMAGE_NAME, as_attachment=False)
def test_database() -> LocationDatabase: return database()
def run(): defaults = {'log': "info"} # Parse any config file specification. We make this parser with add_help=False so # that it doesn't parse -h and print help. conf_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, add_help=False) conf_parser.add_argument("--config", help="Specify config file", metavar='FILE') args, remaining_argv = conf_parser.parse_known_args() # Read configuration file and add it to the defaults hash. if args.config: config = ConfigParser() config.read(args.config) if "Defaults" in config: defaults.update(dict(config.items("Defaults"))) else: logging.error("Bad config file, missing Defaults section") sys.exit(1) # Parse rest of arguments parser = argparse.ArgumentParser( description=__doc__, parents=[conf_parser], ) parser.set_defaults(**defaults) parser.add_argument("--gw-station-id", help="GoodWe station ID", metavar='ID') parser.add_argument("--gw-account", help="GoodWe account", metavar='ACCOUNT') parser.add_argument("--gw-password", help="GoodWe password", metavar='PASSWORD') parser.add_argument("--mqtt-host", help="MQTT hostname", metavar='MQTT_HOST') parser.add_argument("--mqtt-port", help="MQTT port", metavar='MQTT_USER') parser.add_argument("--mqtt-user", help="MQTT username", metavar='MQTT_USER') parser.add_argument("--mqtt-password", help="MQTT password", metavar='MQTT_PASS') parser.add_argument("--mqtt-topic", help="MQTT topic", metavar='MQTT_TOPIC') parser.add_argument("--pvo-system-id", help="PVOutput system ID", metavar='ID') parser.add_argument("--pvo-api-key", help="PVOutput API key", metavar='KEY') parser.add_argument("--pvo-interval", help="PVOutput interval in minutes", type=int, choices=[5, 10, 15]) parser.add_argument("--telegram-token", help="Telegram bot token", metavar='TELEGRAM_TOKEN') parser.add_argument("--telegram-chatid", help="Telegram chat id", metavar='TELEGRAM_CHATID') parser.add_argument("--darksky-api-key", help="Dark Sky Weather API key") parser.add_argument("--openweather-api-key", help="Open Weather API key") parser.add_argument("--log", help="Set log level (default info)", choices=['debug', 'info', 'warning', 'critical']) parser.add_argument("--date", help="Copy all readings (max 14/90 days ago)", metavar='YYYY-MM-DD') parser.add_argument( "--upload-csv", help="Upload all readings from csv file (max 14/90 days ago)") parser.add_argument("--pv-voltage", help="Send pv voltage instead of grid voltage", action='store_true') parser.add_argument("--skip-offline", help="Skip uploads when inverter is offline", action='store_true') parser.add_argument( "--city", help="Sets timezone and skip uploads from dusk till dawn") parser.add_argument( '--csv', help= "Append readings to a Excel compatible CSV file, DATE in the name will be replaced by the current date" ) parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) args = parser.parse_args() # Configure the logging numeric_level = getattr(logging, args.log.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: %s' % loglevel) logging.basicConfig(format='%(levelname)-8s %(message)s', level=numeric_level) logging.debug("gw2pvo version " + __version__) if isinstance(args.skip_offline, str): args.skip_offline = args.skip_offline.lower() in [ 'true', 'yes', 'on', '1' ] if args.upload_csv is None: if args.gw_station_id is None or args.gw_account is None or args.gw_password is None: if args.mqtt_host is None or args.mqtt_topic is None: logging.error( "Missing configuation. Either MQTT configuration or Goodwe (SEMS Portal) credentails need to be provided.\nPlease add either --gw-station-id, --gw-account and --gw-password OR add --mqtt-host and --mqtt-topic (at a minimum). Alternatively, one of these options can also be configured in a configuration file." ) sys.exit(1) if args.city: city = Location(lookup(args.city, database())) os.environ['TZ'] = city.timezone time.tzset() else: city = None logging.debug("Timezone {}".format(datetime.now().astimezone().tzinfo)) # Check if we want to copy old data if args.date: try: copy(args) except KeyboardInterrupt: sys.exit(1) except Exception as exp: logging.error(exp) sys.exit() elif args.upload_csv: try: copy_csv(args) except Exception as exp: logging.error(exp) sys.exit(1) startTime = datetime.now() while True: currentTime = datetime.now() try: run_once(args, city) except KeyboardInterrupt: sys.exit(1) except Exception as exp: errorMsg = ("Failed to publish data PVOutput - " + str(exp)) logging.error(str(currentTime) + " - " + str(errorMsg)) try: telegram_notify(args.telegram_token, args.telegram_chatid, errorMsg) except Exception as exp: logging.error( str(currentTime) + " - Failed to send telegram notification - " + str(exp)) if args.pvo_interval is None: break interval = args.pvo_interval * 60 time.sleep(interval - (datetime.now() - startTime).seconds % interval)
def update_day_curve(): city = lookup(constants.location, database()) sun_info = sun(city.observer, date=datetime.datetime.now()) time_left = (sun_info['sunrise'].hour * 60) + sun_info['sunrise'].minute + 35 time_middle = ((sun_info['sunset'].hour * 60) + sun_info['sunset'].minute + 35) - ((sun_info['sunrise'].hour * 60) + sun_info['sunrise'].minute + 35) + time_left time_now = (datetime.datetime.now().time().hour * 60) + datetime.datetime.now().time().minute data_points = [] # clear screen GB.surface_day_main.fill(constants.black) # draw lines # main seperation line pygame.draw.lines(GB.surface_day_main, constants.gray1, False, [(25, 125), (425, 125)], 3) # left bottom line pygame.draw.lines(GB.surface_day_main, constants.gray2, False, constants.day_points_btm_left, 3) # main top line pygame.draw.lines(GB.surface_day_main, constants.white, False, constants.day_points_top, 3) # right bottom line pygame.draw.lines(GB.surface_day_main, constants.gray2, False, constants.day_points_btm_right, 3) if time_now <= time_left: # its night now, left GB.is_day_time = 0 # calculate index index = constants.map_num(time_now, 0, time_left, 0, 10) index = int(index) + 2 for i in range(0, index): data_points.append(constants.day_points_btm_left[i]) data_points.append((((index - 2) * 10) + 25, 125)) # fill graph pygame.gfxdraw.filled_polygon(GB.surface_day_main, data_points, constants.gray2) # draw circle pygame.draw.circle(GB.surface_day_main, constants.moon_blue, data_points[(index - 1)], 15, 0) elif time_now > time_left and time_now <= time_middle: # its day now # calculate index index = constants.map_num(time_now, time_left, time_middle, 0, 20) index = int(index) + 2 # save index GB.is_day_time = index for i in range(0, index): data_points.append(constants.day_points_top[i]) data_points.append((((index - 2) * 10) + 125, 125)) # fill graphs pygame.gfxdraw.filled_polygon(GB.surface_day_main, constants.day_points_btm_left, constants.gray2) pygame.gfxdraw.filled_polygon(GB.surface_day_main, data_points, constants.white) # draw circle pygame.draw.circle(GB.surface_day_main, constants.yellow, data_points[(index - 1)], 15, 0) elif time_now > time_middle: # its night now, right GB.is_day_time = -1 # calculate index index = constants.map_num(time_now, time_middle, 1440, 0, 10) index = int(index) + 2 for i in range(0, index): data_points.append(constants.day_points_btm_right[i]) data_points.append((((index - 2) * 10) + 325, 125)) # fill graphs pygame.gfxdraw.filled_polygon(GB.surface_day_main, constants.day_points_btm_left, constants.gray2) pygame.gfxdraw.filled_polygon(GB.surface_day_main, constants.day_points_top, constants.white) pygame.gfxdraw.filled_polygon(GB.surface_day_main, data_points, constants.gray2) # draw circle pygame.draw.circle(GB.surface_day_main, constants.moon_blue, data_points[(index - 1)], 15, 0)
import sys, pytz from datetime import date from astral.geocoder import database, lookup from astral.sun import sun city_name = sys.argv[1] city = lookup(city_name, database()) print('Information for %s/%s\n' % (city.name, city.region)) timezone = city.timezone print('Timezone: %s' % timezone) print('Latitude: %.02f; Longitude: %.02f\n' % (city.latitude, city.longitude)) s = sun(city.observer, date=date.today(), tzinfo=pytz.timezone(timezone)) print('Dawn: %s' % str(s['dawn'])) print('Sunrise: %s' % str(s['sunrise'])) print('Noon: %s' % str(s['noon'])) print('Sunset: %s' % str(s['sunset'])) print('Dusk: %s' % str(s['dusk']))
def run_loop(config): delta = 0 base = config["base_path"] debugLog = config["debugLog"] # assumption that this program won't run for weeks so calc dawn/dusk once # check location is in astral db via online documentation city = lookup(config["location"], database()) citysun = sun(city.observer, date=now) Dawn = citysun["dawn"].astimezone(timezone(city.timezone)).time() Dusk = citysun["dusk"].astimezone(timezone(city.timezone)).time() while True: # grab config file try: filepath = config["base_path"] + "/config.yaml" with open(filepath) as f: config = yaml.load(f, Loader=yaml.FullLoader) debugLog = config["debugLog"] except FileNotFoundError: logger.info("--<opening '%s' failed>---", filepath) if debugLog: logger.info(" ") logger.info("=========== start capture ==========") now = datetime.now() startTime = config["start_time"] endTime = config["end_time"] pause = config["time_delay"] if debugLog: logger.info("Pause interval: %s", str(pause)) # set exposure or drop out of loop if night mode nowTime = now.time() if Dawn < nowTime and nowTime < Dusk: # Day if config["shooting_mode"] == "night": if debugLog: logger.info( "Shot cancelled as time is outside time window") continue exposureMode = 'auto' else: # Night exposureMode = 'night' take_shot = check_shot(startTime, endTime) if take_shot is True: path = prepare_dir(base, now) name = '{:%Y%m%d-%H%M%S-}'.format(now) + exposureMode + '.jpg' if debugLog: logger.info("Capturing %s in %s mode", name, exposureMode) fileName = base + "/" + path + "/" + name os_command = make_os_command(config, exposureMode, fileName) os.system(os_command) if debugLog: logger.info("Command: %s", os_command) delta = int((datetime.now() - now).seconds) if debugLog: logger.info("Capture File: %s/%s secs", str(delta), str(pause)) else: if debugLog: logger.info("Shot cancelled as time is outside time window") # night shots take about 10 x shooting time if pause - delta > 0: time.sleep(pause - delta)
from datetime import datetime from astral.geocoder import database, lookup from astral.sun import sun from dateutil import tz loc = lookup("London", database()) print('Location: %s/%s' % (loc.name, loc.region)) print('Timezone: %s' % loc.timezone) print('Latitude: %.02f; Longitute: %.02f\n' % (loc.latitude, loc.longitude)) date_now = datetime.now() s = sun(loc.observer, date=date_now) print("Date: " + date_now.strftime("%d.%m.%Y")) print('Dawn: %s' % s['dawn'].astimezone(tz.tzlocal()).strftime("%H:%M:%S")) print('Sunrise: %s' % s['sunrise'].astimezone(tz.tzlocal()).strftime("%H:%M:%S")) print('Sunset: %s' % s['sunset'].astimezone(tz.tzlocal()).strftime("%H:%M:%S")) print('Dusk: %s' % s['dusk'].astimezone(tz.tzlocal()).strftime("%H:%M:%S"))
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)
class Config: # Motion Detection (MD) config MD_DAY_PIXEL_CHANGE_THRESHOLD = 50 MD_NIGHT_PIXEL_CHANGE_THRESHOLD = 15 MD_IMAGE_CHANGE_THRESHOLD = 0.02 MD_RESIZE_WIDTH = 240 MD_RESOLUTION = (640, 480) MD_MIN_DURATION_S = 5 MD_MAX_DURATION_S = 60 MD_STILL_FPS = 2 MD_MOTION_FPS = 10 MD_STORAGE_PATH = "data/video" MD_STORAGE_MAX_AGE = 30 * 24 * 3600 MD_DAY_BRIGHTNESS = 50 MD_NIGHT_BRIGHTNESS = 65 MD_LOCATION_INFO = lookup("Melbourne", database()) # Thermal Camera (TC) config TC_ENABLED = True TC_ADDR = 0x69 TC_MIN_TEMP_C = 0 TC_MAX_TEMP_C = 50 TC_CHANGE_TEMP_PIXEL_THRESHOLD = 2 TC_CHANGE_TEMP_IMAGE_THRESHOLD_PIXELS = 4 TC_STORAGE_PATH = "data/video/ir" TC_RESOLUTION = (8, 8) TC_MIN_DURATION_S = 3 TC_MAX_DURATION_S = 15 TC_STILL_FPS = 2 TC_MOTION_FPS = 10 # Auto Updater (AD) config AD_INTERVAL_S = 5 * 60 # Temp monitor (TM) config TM_MEASURE_INTERVAL_S = 15 TM_THRESHOLDS_C = { TempRange.HOT: 60, TempRange.VERY_HOT: 70, TempRange.DANGEROUS: 80 } # Fan Controller (FC) config FC_GPIO_PIN = 21 FC_FAN_MIN_TEMP = 50 FC_PWM_MIN_VAL = 0.3 FC_FAN_MAX_TEMP = 65 FC_PWM_MAX_VAL = 1.0 FC_PWM_FREQ_HZ = 25 FC_UPDATE_INTERVAL_S = 15 # Video Classification (VC) config VC_INPUT_SHAPE = (15, 96, 96, 3) # dims: frames, w, h, channels VC_PREPROCESS_CACHE_PATH = './data/cache/' VC_PET_CLASSES = { 'MIA': 1, 'LUNA': 2, 'OTHER': 3, } VC_EVENT_CLASSES = { 'SIGHTING': 1, 'WENT_INSIDE': 2, 'WENT_OUTSIDE': 3, 'HUNT': 4, 'FIGHT': 5, 'TOILET': 6, 'OTHER': 7, } # API API_BIND_ADDR = os.getenv("API_BIND_ADDR") API_TLS_CERT_PATH = os.getenv("API_TLS_CERT_PATH") API_TLS_KEY_PATH = os.getenv("API_TLS_KEY_PATH") API_BASIC_USER = os.getenv("API_BASIC_USER") API_BASIC_PASS = os.getenv("API_BASIC_PASS") # Video Processor (VP) VP_TFLITE_MODEL_PATH = "./data/model/model.tflite" VP_FRAMES_DIR = './data/frames/' VP_PUBLIC_DIR = './data/public/' VP_FFMPEG_THREADS = 1 # Database DB_SQLITE_PATH = "./data/db.sqlite" def __init__(self): self.logger = logging.getLogger('smartpetdoor') self.init_paths() def init_paths(self): os.makedirs(self.MD_STORAGE_PATH, exist_ok=True)
from astral import LocationInfo from astral.geocoder import database, lookup from astral.sun import sun # Configuation CITY = "Austin" # Choose from list of cities in README LED_DAY_BRIGHTNESS = 0.2 # Float from 0.0 (min) to 1.0 (max) LED_NIGHT_BRIGHTNESS= 0.08 # Float from 0.0 (min) to 1.0 (max) # Setup now_utc = datetime.datetime.utcnow() # astral times are in zulu now_local = datetime.datetime.now() year = now_local.date().year month = now_local.date().month day = now_local.date().day city = lookup(CITY,database()) s = sun(city.observer, date=datetime.date(year, month, day)) # query with local day to keep sunset and sunrise on local day not zulu day #times in zulu sunrise = (s["sunrise"]).replace(tzinfo=None) sunset = (s["sunset"]).replace(tzinfo=None) dawn = (s["dawn"]).replace(tzinfo=None) dusk = (s["dusk"]).replace(tzinfo=None) up = sunrise down = sunset if ((now_utc < up) | (now_utc > down)): LED_BRIGHTNESS = LED_NIGHT_BRIGHTNESS print("Nightime. Switching at " + str(up)) elif ((now_utc > up) & (now_utc < down)): LED_BRIGHTNESS = LED_DAY_BRIGHTNESS print("Daytime. Switching at " + str(down)) else:
from http.server import HTTPServer, BaseHTTPRequestHandler from sun_tracker import get_location_info, check_after_sunset, display_city_info, get_sun_info from astral.geocoder import database import datetime notification = 'False' is_connected = 'False' should_break = 'False' # Getting locational info city = get_location_info(database(), 'Warsaw') # Getting info about the sun today sun = get_sun_info(city, datetime.date.today()) now = datetime.datetime.now() hour_now = now.hour hour_ss = sun['sunset'].hour hour_sr = sun['sunrise'].hour status = check_after_sunset(hour_sr, hour_ss, hour_now) status = True class Server(BaseHTTPRequestHandler): def do_GET(self): global notification, status, is_connected, should_break if self.path == '/': self.send_response(200) self.send_header('content-type', 'text/html')