Exemple #1
0
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)
Exemple #2
0
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)
Exemple #3
0
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)
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
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
Exemple #8
0
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})
Exemple #10
0
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()
Exemple #11
0
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)
Exemple #12
0
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])