class plugin: ''' A class to display the time of sunrise/sunset Uses the astral library to retrieve information... ''' def __init__(self, config): ''' Initializations for the startup of the weather forecast ''' # Get plugin name (according to the folder, it is contained in) self.name = os.path.dirname(__file__).split('/')[-1] self.pretty_name = "Sunrise" self.description = "Displays the current times of sunrise and sunset." self.astral_at_location = Astral()[config.get('plugin_' + self.name, 'location')] # Choose language to display sunrise language = config.get('plugin_time_default', 'language') if language == 'german': self.taw = wcp_time_german.time_german() elif language == 'dutch': self.taw = wcp_time_dutch.time_dutch() elif language == 'swiss_german': self.taw = wcp_swiss_german.time_swiss_german() else: print('Could not detect language: ' + language + '.') print('Choosing default: german') self.taw = wcp_time_german.time_german() self.bg_color_index = 0 # default background color: black self.word_color_index = 2 # default word color: warm white self.minute_color_index = 2 # default minute color: warm white def run(self, wcd, wci): ''' Displaying current time for sunrise/sunset ''' # Get data of sunrise sun_data = self.astral_at_location.sun(date=datetime.datetime.now(), local=True) # Display data of sunrise wcd.animate(self.name, 'sunrise', invert=True) wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = self.taw.get_time(sun_data['sunrise'], withPrefix=False) wcd.setColorBy1DCoordinates(wcd.strip, taw_indices, wcc.colors[self.word_color_index]) wcd.show() time.sleep(3) # Display data of sunset wcd.animate(self.name, 'sunrise') wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = self.taw.get_time(sun_data['sunset'], withPrefix=False) wcd.setColorBy1DCoordinates(wcd.strip, taw_indices, wcc.colors[self.word_color_index]) wcd.show() time.sleep(3) # Display current moon phase moon_phase = int(self.astral_at_location.moon_phase(datetime.datetime.now())) for i in range(0, moon_phase): wcd.showIcon('sunrise', 'moon_'+str(i).zfill(2)) time.sleep(0.1) time.sleep(3)
class Sun: city_name: str = attr.ib() def __attrs_post_init__(self): self.loc = Astral().geocoder[self.city_name] def get_time(self, name, date=None, offset: timedelta = timedelta(seconds=0)) -> TimeTracker: date = date or CustomTime.now().date() next_time = self.loc.sun(date)[name] + offset while next_time <= CustomTime.now(): date = date + timedelta(days=1) + offset next_time = self.loc.sun(date)[name] return TimeTracker(next_time) def rule(self, name, offset: timedelta = timedelta(seconds=0)): assert name in ['sunrise', 'dusk', 'sunset', 'dawn'] def deco(foo): @wraps(foo) async def wrapper(*args, **kwargs) -> asyncio.Task: @autils.endless_loop async def _loop(): await self.get_time(name, offset=offset).wait() await autils.async_run(foo, *args, **kwargs) return await _loop() return wrapper return deco def rule_sunrise(self, offset=timedelta(seconds=0)): return self.rule('sunrise', offset=offset) def rule_dusk(self, offset=timedelta(seconds=0)): return self.rule('dusk', offset=offset) def rule_sunset(self, offset=timedelta(seconds=0)): return self.rule('sunset', offset=offset) def rule_dawn(self, offset=timedelta(seconds=0)): return self.rule('dawn', offset=offset)
class plugin: ''' A class to display the time of sunrise/sunset Uses the astral library to retrieve information... ''' def __init__(self, config): ''' Initializations for the startup of the weather forecast ''' # Get plugin name (according to the folder, it is contained in) self.name = os.path.dirname(__file__).split('/')[-1] self.astral_at_location = Astral()[config.get('plugin_' + self.name, 'location')] # Choose language to display sunrise language = config.get('plugin_time_default', 'language') if language == 'german': self.taw = wcp_time_german.time_german() elif language == 'dutch': self.taw = wcp_time_dutch.time_dutch() elif language == 'swiss_german': self.taw = wcp_swiss_german.time_swiss_german() else: print('Could not detect language: ' + language + '.') print('Choosing default: german') self.taw = wcp_time_german.time_german() self.bg_color_index = 0 # default background color: black self.word_color_index = 2 # default word color: warm white self.minute_color_index = 2 # default minute color: warm white def run(self, wcd, wci): ''' Displaying current time for sunrise/sunset ''' # Get data of sunrise sun_data = self.astral_at_location.sun(date=datetime.datetime.now(), local=True) # Display data of sunrise wcd.animate(self.name, 'sunrise', invert=True) wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = self.taw.get_time(sun_data['sunrise'], withPrefix=False) wcd.setColorBy1DCoordinates(wcd.strip, taw_indices, wcc.colors[self.word_color_index]) wcd.show() time.sleep(3) # Display data of sunset wcd.animate(self.name, 'sunrise') wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = self.taw.get_time(sun_data['sunset'], withPrefix=False) wcd.setColorBy1DCoordinates(wcd.strip, taw_indices, wcc.colors[self.word_color_index]) wcd.show() time.sleep(3) # Display current moon phase moon_phase = int(self.astral_at_location.moon_phase(datetime.datetime.now())) for i in range(0, moon_phase): wcd.showIcon('sunrise', 'moon_'+str(i).zfill(2)) time.sleep(0.1) time.sleep(3)
class plugin: """ A class to display the time of sunrise/sunset Uses the astral library to retrieve information... """ def __init__(self, config): """ Initializations for the startup of the weather forecast """ # Get plugin name (according to the folder, it is contained in) self.name = os.path.dirname(__file__).split('/')[-1] self.pretty_name = "Sunrise" self.description = "Displays the current times of sunrise and sunset." self.astral_at_location = Astral()[config.get('plugin_' + self.name, 'location')] self.bg_color_index = 0 # default background color: black self.word_color_index = 2 # default word color: warm white self.minute_color_index = 2 # default minute color: warm white def run(self, wcd, wci): """ Displaying current time for sunrise/sunset """ # Get data of sunrise sun_data = self.astral_at_location.sun(date=datetime.datetime.now(), local=True) # Display data of sunrise wcd.animate(self.name, 'sunrise', invert=True) wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = wcd.taw.get_time(sun_data['sunrise'], purist=True) wcd.setColorBy1DCoordinates(taw_indices, wcc.colors[self.word_color_index]) wcd.show() if wci.waitForExit(3.0): return # Display data of sunset wcd.animate(self.name, 'sunrise') wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = wcd.taw.get_time(sun_data['sunset'], purist=True) wcd.setColorBy1DCoordinates(taw_indices, wcc.colors[self.word_color_index]) wcd.show() if wci.waitForExit(3.0): return # Display current moon phase moon_phase = int( self.astral_at_location.moon_phase(datetime.datetime.now())) for i in range(0, moon_phase): wcd.showIcon('sunrise', 'moon_' + str(i).zfill(2)) if wci.waitForExit(0.1): return if wci.waitForExit(3.0): return
def daytime(): """ Compute whether it is currently daytime based on current location """ city = Astral()[CITY] sundata = city.sun() sunrise = sundata['sunrise'] + timedelta(minutes=DELTA) sunset = sundata['sunset'] - timedelta(minutes=DELTA) now = datetime.now(sunrise.tzinfo) return sunrise < now < sunset
class plugin: """ A class to display the time of sunrise/sunset Uses the astral library to retrieve information... """ def __init__(self, config): """ Initializations for the startup of the weather forecast """ # Get plugin name (according to the folder, it is contained in) self.name = os.path.dirname(__file__).split('/')[-1] self.pretty_name = "Sunrise" self.description = "Displays the current times of sunrise and sunset." self.astral_at_location = Astral()[config.get('plugin_' + self.name, 'location')] self.bg_color_index = 0 # default background color: black self.word_color_index = 2 # default word color: warm white self.minute_color_index = 2 # default minute color: warm white def run(self, wcd, wci): """ Displaying current time for sunrise/sunset """ # Get data of sunrise sun_data = self.astral_at_location.sun(date=datetime.datetime.now(), local=True) # Display data of sunrise wcd.animate(self.name, 'sunrise', invert=True) wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = wcd.taw.get_time(sun_data['sunrise'], purist=True) wcd.setColorBy1DCoordinates(wcd.strip, taw_indices, wcc.colors[self.word_color_index]) wcd.show() if wci.waitForExit(3.0): return # Display data of sunset wcd.animate(self.name, 'sunrise') wcd.setColorToAll(wcc.colors[self.bg_color_index], includeMinutes=True) taw_indices = wcd.taw.get_time(sun_data['sunset'], purist=True) wcd.setColorBy1DCoordinates(wcd.strip, taw_indices, wcc.colors[self.word_color_index]) wcd.show() if wci.waitForExit(3.0): return # Display current moon phase moon_phase = int(self.astral_at_location.moon_phase(datetime.datetime.now())) for i in range(0, moon_phase): wcd.showIcon('sunrise', 'moon_' + str(i).zfill(2)) if wci.waitForExit(0.1): return if wci.waitForExit(3.0): return
class SunEventGenerator(object): def __init__(self, city, baseUrl, value, zone=0): self.city = Astral()[city] self.url = baseUrl+'/setEvent/' self.value = value self.zone = zone def setSunset(self): return self._setEvent('sunset') def setSunrise(self): return self._setEvent('sunrise') def _setEvent(self, event): params = {} if isinstance(self.value, int): params['mono'] = self.value else: params['red'] = self.value[0] params['green'] = self.value[1] params['blue'] = self.value[2] params['delay'] = self._secondsUntilSunEvent(event) params['zone'] = self.zone return requests.get(url=self.url, params=params) def secondsUntilSunset(self): return self._secondsUntilSunEvent('sunset') def secondsUntilSunrise(self): return self._secondsUntilSunEvent('sunrise') def _secondsUntilSunEvent(self, event): now = self.city.tz.localize(datetime.now()) seconds = int(((self.city.sun(date=now, local=True))[event] - now).total_seconds()) if seconds < 0: seconds = int((self.city.sun(date=now+timedelta(days=1), local=True)[event] - now).total_seconds()) return seconds
def refresh_times(): """Refreshes the sun times in the times_dict""" global times_dict date = arrow.utcnow().to('US/Pacific').format('YYYY-MM-DD') city = Astral()['Seattle'] sun = city.sun(date=datetime.date(int(date[:4]), int(date[5:-3]), int(date[8:])), local=True) for key in times_dict: times_dict[key] = sun[key.lower()] for key, value in times_dict.items(): string = key + ' - ' + arrow.get(value).format('h:m A') times_dict[key] = string
def fire_minute(self): city = Astral()[self.config.get("astral", "city")] sun = city.sun() self.log.debug(sun) delta = int(time.time()) - int(time.mktime(sun["sunrise"].timetuple())) + 30 if delta > 0: self.log.info("Sunrise was {0} minutes ago".format(delta // 60)) else: self.log.info("Sunrise in {0} minutes".format(-(delta // 60))) self.pluginapi.value_update("1", {"Sunrise delta": delta // 60}) delta = int(time.time()) - int(time.mktime(sun["sunset"].timetuple())) + 30 if delta > 0: self.log.info("Sunset was {0} minutes ago".format(delta // 60)) else: self.log.info("Sunset in {0} minutes".format(-(delta // 60))) self.pluginapi.value_update("1", {"Sunset delta": delta // 60}) delta = int(time.time()) - int(time.mktime(sun["dawn"].timetuple())) + 30 if delta > 0: self.log.info("Dawn was {0} minutes ago".format(delta // 60)) else: self.log.info("Dawn in {0} minutes".format(-(delta // 60))) self.pluginapi.value_update("1", {"Dawn delta": delta // 60}) delta = int(time.time()) - int(time.mktime(sun["dusk"].timetuple())) + 30 if delta > 0: self.log.info("Dusk was {0} minutes ago".format(delta // 60)) else: self.log.info("Dusk in {0} minutes".format(-(delta // 60))) self.pluginapi.value_update("1", {"Dusk delta": delta // 60}) delta = int(time.time()) - int(time.mktime(sun["noon"].timetuple())) + 30 if delta > 0: self.log.info("Solar noon was {0} minutes ago".format(delta // 60)) else: self.log.info("Solar noon in {0} minutes".format(-(delta // 60))) self.pluginapi.value_update("1", {"Solar noon delta": delta // 60})
print('// 0: sunrise hour') print('// 1: sunrise minute') print('// 2: sunset hour') print('// 3: sunset minute') print('// Times are Local, but ignore daylight saving!') print('// (local is good for humans, no DST it good for our simple RTC)') print('// Times are computed for the year 2017, so there maybe 1-2 minutes') print('// error for other years, and 2-3 minutes for leap years.') print('const uint8_t sunset_sunrise_times [][] = {') utc_tz = tz.gettz('UTC') local_tz = tz.gettz(city.timezone) for day in range(1, 366): date = (datetime.date.fromordinal(day)).replace(year=2017) sun = city.sun(date, local=False) if day != 365: sep = ',' else: sep = ' ' # Get sunrise and sunset times in UTC (see "local=False" above) sunrise = sun['sunrise'] sunset = sun['sunset'] # Convert to local (Atral drop the tzinfo when using local, so DST is not # accessible --> we need to redo the job ourselves) utc_sunrise = sunrise.replace(tzinfo=utc_tz) utc_sunset = sunset.replace(tzinfo=utc_tz) local_sunrise = utc_sunrise.astimezone(local_tz) local_sunset = utc_sunset.astimezone(local_tz) local_sunrise_nodst = local_sunrise - local_sunrise.dst() local_sunset_nodst = local_sunset - local_sunset.dst()
class App(): def __init__(self): # DaemonRunner config items self.stdin_path = '/dev/null' self.stdout_path = '/dev/tty' self.stderr_path = '/dev/tty' self.pidfile_path = '/tmp/phaos.pid' self.pidfile_timeout = 5 # Read the config file config = ConfigParser.ConfigParser() # Don't mess with casing of config items config.optionxform = str config.readfp(open('phaos.cfg')) # Frequency to poll the devices self.poll_interval = config.getfloat('General', 'poll_interval') # Hue hostname (reserved IP) self.hue_hostname = config.get('General', 'bridge_hostname') # Current city self.city_name = config.get('General', 'city') # Lights to be controlled self.lights = config.items('Lights') # Groups/rooms to be controlled self.groups = config.items('Groups') # Devices to be scanned self.devices = config.items('Devices') self.log_file = '/var/log/phaos.log' # Store the city info and set the timezone self.city = Astral()[self.city_name] os.environ['TZ'] = self.city.timezone # Start the count as all devices self.count = len(self.devices) def run(self): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', filename=self.log_file, filemode='a') logging.info("Starting - tracking %s devices", self.count) while True: self.main() time.sleep(self.poll_interval) def main(self): previous_count = self.count # Arping the devices packets = [] for ip, mac in self.devices: ans, unans = srp(Ether(dst=mac) / ARP(pdst=ip), timeout=2, verbose=False) # Track the answers for pair in ans: packets.append(pair) current_count = len(packets) # Turn on/off the lights given the devices logging.info("Previous count: %s - Current count %s", previous_count, current_count) if previous_count > 0 and current_count == 0: self.set_lights(False) elif previous_count == 0 and current_count > 0: self.set_lights(True) # Track current count to file self.count = current_count def set_lights(self, on=True): bridge = Bridge(self.hue_hostname) # Turn on/off all of the configured lights for light, time_config in self.lights: # Only change them if the timing info matches if self.check_time_config(time_config): Light(bridge, light).on = on # Turn on/off all of the configured groups for group, time_config in self.groups: if self.check_time_config(time_config): Group(bridge, group).on = on def check_time_config(self, config): today_sun = self.city.sun(local=True) now = datetime.datetime.now(today_sun['dusk'].tzinfo) if config.lower() == 'day': # After dawn but before dusk return now > today_sun['dawn'] and now < today_sun['dusk'] elif config.lower() == 'night': # Before sunrise or after dusk return now < today_sun['dawn'] or now > today_sun['dusk'] elif config.lower() == 'always': # Always return True else: # Try to parse config as timespan try: # Get the from/to time by spliting times = config.split('to') if len(times) != 2: logging.error( 'Time frame must be in the format: H:M:S to H:M:S, e.g. 10:00:00 to 17:00:00' ) return False from_time = datetime.datetime.strptime(times[0].strip(), "%H:%M:%S") from_time = now.replace(hour=from_time.hour, minute=from_time.minute, second=from_time.second) to_time = datetime.datetime.strptime(times[1].strip(), "%H:%M:%S") to_time = now.replace(hour=to_time.hour, minute=to_time.minute, second=to_time.second) if from_time < to_time: # From time is earlier in the day (during the day) # After from time and before to time return now > from_time and now < to_time else: # From time is later in the day (over night) # Before to time or after from time return now < to_time or now > from_time except ValueError: logging.info("Unknown time config: %s", config)
class MapDrawer: def __init__(self, city, log=None): self._astral = Astral() self._astral.solar_depression = 'civil' self._city = city self._astral = self._astral[self._city] self._room_info = log def draw(self, handle): handle = self.draw_room_wall(handle) handle = self.draw_sensors(handle) return handle def draw_sensors(self, handle): handle = self.draw_motion_sensor(handle) handle = self.draw_noise_sensor(handle) handle = self.draw_light_sensor(handle) handle = self.draw_thermometer(handle) handle = self.draw_humidity(handle) handle = self.draw_vaccum_activity(handle) handle = self.draw_smoke_detector(handle) handle = self.draw_openings(handle) return handle def draw_openings(self, handle): if self._room_info.door == OpeningState.OPEN: handle = self.draw_door_sensor(handle) if self._room_info.shutter == OpeningState.OPEN: handle = self.draw_shutter_sensor(handle) return handle def draw_date(self, handle, x=90, y=246, size='15', color='black'): hour = datetime.datetime.now().strftime('%H:%M:%S') day_of_week = get_day_of_week() season = get_season() season_icon = fa.icons["snowflake"] if season == 'spring': season_icon = fa.icons["yelp"] elif season == 'summer': season_icon = fa.icons["sun"] elif season == 'fall': season_icon = fa.icons["envira"] utc = pytz.UTC sun = self._astral.sun(date=datetime.datetime.now(), local=True) sun_icon = fa.icons["moon"] if sun['sunrise'].replace( tzinfo=utc) < datetime.datetime.now().replace( tzinfo=utc) < sun['sunset'].replace(tzinfo=utc): sun_icon = fa.icons["sun"] text = day_of_week + ' ' + hour + ' ' + sun_icon + ' ' + season_icon handle = self.draw_text(handle, text, x, y, size, color) return handle def draw_door_sensor(self, handle): return handle def draw_shutter_sensor(self, handle): return handle def draw_vaccum_activity(self, handle): return handle def draw_light_icon(self, handle, x, y, size='15', color='yellow'): if self._room_info.light: handle = self.draw_icon(handle, 'lightbulb', x, y, size, color) return handle def draw_motion_icon(self, handle, x, y, size='15', color='black'): if self._room_info.motion: handle = self.draw_icon(handle, 'eye', x, y, size, color) return handle def draw_noise_icon(self, handle, x, y, size='15', color='black'): if self._room_info.noise: handle = self.draw_icon(handle, 'volume-up', x, y, size, color) return handle def draw_vaccum_icon(self, handle, x, y, size='15', color='black'): if self._room_info.vaccum: handle = self.draw_icon(handle, 'codiepie', x, y, size, color) return handle def draw_drop_icon(self, handle, x, y, size='15', color='blue'): if self._room_info.humidity: handle = self.draw_icon(handle, 'tint', x, y, size, color) return handle def draw_smoke_icon(self, handle, x, y, size='15', color='lightgray'): if self._room_info.gaz == MonoxideState.MODERATE: handle = self.draw_icon(handle, 'cloud', x, y, size, color) elif self._room_info.gaz == MonoxideState.DANGEROUS: handle = self.draw_icon(handle, 'cloud', x, y, size, 'grey') else: handle = self.draw_icon(handle, 'cloud', x, y, size, 'white') return handle def draw_thermometer_icon(self, handle, x, y, size='15'): if self._room_info.temperature is not None: temperature = int(self._room_info.temperature) if temperature < 4: color = 'cyan' icon = 'snowflake' x -= 4 elif temperature < 18: color = 'blue' icon = 'thermometer-empty' elif temperature <= 21: color = 'orange' icon = 'thermometer-half' else: color = 'red' icon = 'thermometer-full' handle = self.draw_icon(handle, icon, x, y, size, color) return handle def draw_pet_icon(self, handle, x, y, size='15', color='black'): handle = self.draw_icon(handle, 'paw', x, y, size, color) return handle def draw_context(self, handle, icon, x=10, y=246, size='30', color='black'): handle = self.draw_icon(handle, icon, x, y, size, color) return handle def draw_icon(self, handle, icon, x, y, size='15', color='black'): handle.add( handle.text(fa.icons[icon], insert=(x, y), fill=color, font_size=size + 'px')) return handle def draw_text(self, handle, text, x, y, size='15', color='black'): handle.add( handle.text(text, insert=(x, y), fill=color, font_size=size + 'px')) return handle def draw_door(self, handle, x1, y1, x2, y2, width="2", color="white"): handle.add( handle.line((x1, y1), (x2, y2), stroke_width=width, stroke=color)) return handle def print_all_fontawesome(self): for icon in fa.icons: print(icon + ' ' + fa.icons[icon])