Exemplo n.º 1
0
def news(news_source: str = 'fox') -> None:
    """Says news around the user's location.

    Args:
        news_source: Source from where the news has to be fetched. Defaults to ``fox``.
    """
    if not env.news_api:
        logger.warning("News apikey not found.")
        support.no_env_vars()
        return

    sys.stdout.write(f'\rGetting news from {news_source} news.')
    news_client = NewsApiClient(api_key=env.news_api)
    try:
        all_articles = news_client.get_top_headlines(
            sources=f'{news_source}-news')
    except newsapi_exception.NewsAPIException:
        speaker.speak(
            text=f"I wasn't able to get the news {env.title}! "
            "I think the News API broke, you may try after sometime.")
        return

    speaker.speak(text="News around you!")
    speaker.speak(text=' '.join(
        [article['title'] for article in all_articles['articles']]))
    if shared.called_by_offline:
        return

    if shared.called['report'] or shared.called['time_travel']:
        speaker.speak(run=True)
Exemplo n.º 2
0
def locate(phrase: str) -> None:
    """Locates an Apple device using icloud api for python.

    Args:
        phrase: Takes the voice recognized statement as argument and extracts device name from it.
    """
    if not (target_device := device_selector(phrase=phrase)):
        support.no_env_vars()
        return
Exemplo n.º 3
0
def robinhood() -> None:
    """Gets investment details from robinhood API."""
    if not all([env.robinhood_user, env.robinhood_pass, env.robinhood_qr]):
        logger.warning("Robinhood username, password or QR code not found.")
        support.no_env_vars()
        return

    sys.stdout.write("\rGetting your investment details.")
    rh = Robinhood()
    rh.login(username=env.robinhood_user,
             password=env.robinhood_pass,
             qr_code=env.robinhood_qr)
    raw_result = rh.positions()
    result = raw_result["results"]
    stock_value = watcher(rh, result)
    speaker.speak(text=stock_value)
Exemplo n.º 4
0
def github(phrase: str) -> None:
    """Pre-process to check the phrase received and call the ``GitHub`` function as necessary.

    Args:
        phrase: Takes the phrase spoken as an argument.
    """
    if 'update yourself' in phrase or 'update your self' in phrase:
        update()
        return

    if not all([env.git_user, env.git_pass]):
        logger.warning("Github username or token not found.")
        support.no_env_vars()
        return
    auth = HTTPBasicAuth(env.git_user, env.git_pass)
    response = requests.get(
        'https://api.github.com/user/repos?type=all&per_page=100',
        auth=auth).json()
    result, repos, total, forked, private, archived, licensed = [], [], 0, 0, 0, 0, 0
    for i in range(len(response)):
        total += 1
        forked += 1 if response[i]['fork'] else 0
        private += 1 if response[i]['private'] else 0
        archived += 1 if response[i]['archived'] else 0
        licensed += 1 if response[i]['license'] else 0
        repos.append({
            response[i]['name'].replace('_', ' ').replace('-', ' '):
            response[i]['clone_url']
        })
    if 'how many' in phrase:
        speaker.speak(
            text=
            f'You have {total} repositories {env.title}, out of which {forked} are forked, {private} are private, '
            f'{licensed} are licensed, and {archived} archived.')
    elif not shared.called_by_offline:
        [
            result.append(clone_url) if clone_url not in result
            and re.search(rf'\b{word}\b', repo.lower()) else None
            for word in phrase.lower().split() for item in repos
            for repo, clone_url in item.items()
        ]
        if result:
            github_controller(target=result)
        else:
            speaker.speak(text=f"Sorry {env.title}! I did not find that repo.")
Exemplo n.º 5
0
def car(phrase: str) -> None:
    """Controls the car to lock, unlock or remote start.

    Args:
        phrase: Takes the phrase spoken as an argument.

    See Also:
        API climate controls: 31 is LO, 57 is HOT
        Car Climate controls: 58 is LO, 84 is HOT
    """
    if not all([env.car_email, env.car_pass, env.car_pin]):
        logger.warning("InControl email or password or PIN not found.")
        support.no_env_vars()
        return

    disconnected = f"I wasn't able to connect your car {env.title}! Please check the logs for more information."

    if "start" in phrase or "set" in phrase or "turn on" in phrase:
        if not shared.called_by_offline:
            playsound(sound=indicators.exhaust, block=False)
        extras = ""
        if target_temp := support.extract_nos(input_=phrase, method=int):
            if target_temp < 57:
                target_temp = 57
            elif target_temp > 83:
                target_temp = 83
        elif "high" in phrase or "highest" in phrase:
            target_temp = 83
        elif "low" in phrase or "lowest" in phrase:
            target_temp = 57
        else:
            if vehicle_position := vehicle(operation="LOCATE_INTERNAL"):
                current_temp, target_temp = get_current_temp(
                    location=vehicle_position)
                extras += f"Your car is in {vehicle_position['city']} {vehicle_position['state']}, where the " \
                          f"current temperature is {current_temp}, so "
            else:
Exemplo n.º 6
0
def lights(phrase: str) -> Union[None, NoReturn]:
    """Controller for smart lights.

    Args:
        phrase: Takes the voice recognized statement as argument.
    """
    if not vpn_checker():
        return

    if not os.path.isfile(fileio.smart_devices):
        logger.warning(f"{fileio.smart_devices} not found.")
        support.no_env_vars()
        return

    try:
        with open(fileio.smart_devices) as file:
            smart_devices = yaml.load(stream=file,
                                      Loader=yaml.FullLoader) or {}
    except yaml.YAMLError as error:
        logger.error(error)
        speaker.speak(
            text=
            f"I'm sorry {env.title}! I wasn't able to read the source information. "
            "Please check the logs.")
        return

    if not any(smart_devices):
        logger.warning(f"{fileio.smart_devices} is empty.")
        support.no_env_vars()
        return

    phrase = phrase.lower()

    def turn_off(host: str) -> NoReturn:
        """Turns off the device.

        Args:
            host: Takes target device IP address as an argument.
        """
        smart_lights.MagicHomeApi(device_ip=host,
                                  device_type=1,
                                  operation='Turn Off').turn_off()

    def warm(host: str) -> NoReturn:
        """Sets lights to warm/yellow.

        Args:
            host: Takes target device IP address as an argument.
        """
        smart_lights.MagicHomeApi(device_ip=host,
                                  device_type=1,
                                  operation='Warm Lights').update_device(
                                      r=0, g=0, b=0, warm_white=255)

    def cool(host: str) -> NoReturn:
        """Sets lights to cool/white.

        Args:
            host: Takes target device IP address as an argument.
        """
        smart_lights.MagicHomeApi(device_ip=host,
                                  device_type=2,
                                  operation='Cool Lights').update_device(
                                      r=255,
                                      g=255,
                                      b=255,
                                      warm_white=255,
                                      cool_white=255)

    def preset(host: str, value: int) -> NoReturn:
        """Changes light colors to preset values.

        Args:
            host: Takes target device IP address as an argument.
            value: Preset value extracted from list of verified values.
        """
        smart_lights.MagicHomeApi(
            device_ip=host, device_type=2,
            operation='Preset Values').send_preset_function(
                preset_number=value, speed=101)

    def lumen(host: str, rgb: int = 255) -> NoReturn:
        """Sets lights to custom brightness.

        Args:
            host: Takes target device IP address as an argument.
            rgb: Red, Green andBlue values to alter the brightness.
        """
        args = {'r': 255, 'g': 255, 'b': 255, 'warm_white': rgb}
        smart_lights.MagicHomeApi(
            device_ip=host, device_type=1,
            operation='Custom Brightness').update_device(**args)

    if 'all' in phrase.split():
        # Checking for list since lights are inserted as a list and tv as string
        host_names = [
            value for key, value in smart_devices.items()
            if isinstance(value, list)
        ]
        light_location = ""
    else:
        # Get the closest matching name provided in smart_devices.yaml compared to what's requested by the user
        light_location = support.get_closest_match(text=phrase,
                                                   match_list=list(
                                                       smart_devices.keys()))
        host_names = [smart_devices.get(light_location)]
        light_location = light_location.replace('_', ' ').replace('-', '')

    host_names = support.matrix_to_flat_list(input_=host_names)
    host_names = list(filter(None, host_names))
    if light_location and not host_names:
        logger.warning(
            f"No hostname values found for {light_location} in {fileio.smart_devices}"
        )
        speaker.speak(
            text=
            f"I'm sorry {env.title}! You haven't mentioned the host names of '{light_location}' lights."
        )
        return
    if not host_names:
        Thread(target=support.unrecognized_dumper, args=[{
            'LIGHTS': phrase
        }]).start()
        speaker.speak(text=f"I'm not sure which lights you meant {env.title}!")
        return

    host_ip = [
        support.hostname_to_ip(hostname=hostname) for hostname in host_names
    ]
    # host_ip = list(filter(None, host_ip))
    host_ip = support.matrix_to_flat_list(input_=host_ip)
    if not host_ip:
        plural = 'lights' if len(host_ip) > 1 else 'light'
        speaker.speak(
            text=
            f"I wasn't able to connect to your {light_location} {plural} {env.title}! "
            f"{support.number_to_words(input_=len(host_ip), capitalize=True)} lights appear to be "
            "powered off.")
        return

    def avail_check(function_to_call: Callable) -> NoReturn:
        """Speaks an error message if any of the lights aren't reachable.

        Args:
            function_to_call: Takes the function/method that has to be called as an argument.
        """
        status = ThreadPool(processes=1).apply_async(func=thread_worker,
                                                     args=[function_to_call])
        speaker.speak(run=True)
        if failed := status.get(timeout=5):
            plural_ = "lights aren't available right now!" if failed > 1 else "light isn't available right now!"
            speaker.speak(
                text=
                f"I'm sorry sir! {support.number_to_words(input_=failed, capitalize=True)} {plural_}"
            )
Exemplo n.º 7
0
def television(phrase: str) -> None:
    """Controls all actions on a TV (LG Web OS).

    Args:
        phrase: Takes the voice recognized statement as argument.
    """
    if not vpn_checker():
        return

    if not os.path.isfile(fileio.smart_devices):
        logger.warning(f"{fileio.smart_devices} not found.")
        support.no_env_vars()
        return

    try:
        with open(fileio.smart_devices) as file:
            smart_devices = yaml.load(stream=file,
                                      Loader=yaml.FullLoader) or {}
    except yaml.YAMLError as error:
        logger.error(error)
        speaker.speak(
            text=
            f"I'm sorry {env.title}! I was unable to read your TV's source information."
        )
        return

    if not env.tv_mac or not env.tv_client_key:
        logger.warning("IP, MacAddress [or] ClientKey not found.")
        support.no_env_vars()
        return

    tv_ip_list = support.hostname_to_ip(
        hostname=smart_devices.get('tv', 'LGWEBOSTV'))
    tv_ip_list = list(filter(None, tv_ip_list))
    if not tv_ip_list:
        speaker.speak(
            text=
            f"I'm sorry {env.title}! I wasn't able to get the IP address of your TV."
        )
        return

    phrase_exc = phrase.replace('TV', '')
    phrase_lower = phrase_exc.lower()

    def tv_status(attempt: int = 0) -> str:
        """Pings the tv and returns the status. 0 if able to ping, 256 if unable to ping.

        Args:
            attempt: Takes iteration count as an argument.

        Returns:
            int:
            Returns the reachable IP address from the list.
        """
        for ip in tv_ip_list:
            if env.macos:
                if tv_stat := os.system(
                        f"ping -c 1 -t 2 {ip} >/dev/null 2>&1"):
                    logger.error(
                        f"Connection timed out on {ip}. Ping result: {tv_stat}"
                    ) if not attempt else None
                else:
                    return ip
            else:
                if tv_stat := os.system(f"ping -c 1 -t 2 {ip} > NUL"):
                    logger.error(
                        f"Connection timed out on {ip}. Ping result: {tv_stat}"
                    ) if not attempt else None
                else:
Exemplo n.º 8
0
def weather(phrase: str = None) -> None:
    """Says weather at any location if a specific location is mentioned.

    Says weather at current location by getting IP using reverse geocoding if no place is received.

    Args:
        phrase: Takes the phrase spoken as an argument.
    """
    if not env.weather_api:
        logger.warning("Weather apikey not found.")
        support.no_env_vars()
        return

    place = None
    if phrase:
        place = support.get_capitalized(phrase=phrase)
        phrase = phrase.lower()
    sys.stdout.write('\rGetting your weather info')
    if place:
        desired_location = geo_locator.geocode(place)
        coordinates = desired_location.latitude, desired_location.longitude
        located = geo_locator.reverse(coordinates, language='en')
        address = located.raw['address']
        city = address.get('city')
        state = address.get('state')
        lat = located.latitude
        lon = located.longitude
    else:
        try:
            with open(fileio.location) as file:
                current_location = yaml.load(stream=file,
                                             Loader=yaml.FullLoader)
        except yaml.YAMLError as error:
            logger.error(error)
            speaker.speak(
                text=
                f"I'm sorry {env.title}! I wasn't able to read your location.")
            return

        address = current_location.get('address', {})
        city = address.get('city', address.get('hamlet', 'Unknown'))
        state = address.get('state', 'Unknown')
        lat = current_location['latitude']
        lon = current_location['longitude']
    weather_url = f'https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude=minutely,' \
                  f'hourly&appid={env.weather_api}'
    try:
        response = json.loads(urllib.request.urlopen(
            url=weather_url).read())  # loads the response in a json
    except (urllib.error.HTTPError, urllib.error.URLError) as error:
        logger.error(error)
        speaker.speak(
            text=
            f"I'm sorry {env.title}! I ran into an exception. Please check your logs."
        )
        return

    weather_location = f'{city} {state}'.replace(
        'None', '') if city != state else city or state

    if phrase and any(match_word in phrase for match_word in [
            'tomorrow', 'day after', 'next week', 'tonight', 'afternoon',
            'evening'
    ]):
        if 'tonight' in phrase:
            key = 0
            tell = 'tonight'
        elif 'day after' in phrase:
            key = 2
            tell = 'day after tomorrow '
        elif 'tomorrow' in phrase:
            key = 1
            tell = 'tomorrow '
        elif 'next week' in phrase:
            key = -1
            next_week = datetime.fromtimestamp(
                response['daily'][-1]['dt']).strftime("%A, %B %d")
            tell = f"on {' '.join(next_week.split()[0:-1])} {engine().ordinal(next_week.split()[-1])}"
        else:
            key = 0
            tell = 'today '
        if 'morning' in phrase:
            when = 'morn'
            tell += 'morning'
        elif 'evening' in phrase:
            when = 'eve'
            tell += 'evening'
        elif 'tonight' in phrase:
            when = 'night'
        elif 'night' in phrase:
            when = 'night'
            tell += 'night'
        else:
            when = 'day'
            tell += ''
        if 'alerts' in response:
            alerts = response['alerts'][0]['event']
            start_alert = datetime.fromtimestamp(
                response['alerts'][0]['start']).strftime("%I:%M %p")
            end_alert = datetime.fromtimestamp(
                response['alerts'][0]['end']).strftime("%I:%M %p")
        else:
            alerts, start_alert, end_alert = None, None, None
        during_key = response['daily'][key]
        condition = during_key['weather'][0]['description']
        high = int(temperature.k2f(during_key['temp']['max']))
        low = int(temperature.k2f(during_key['temp']['min']))
        temp_f = int(temperature.k2f(during_key['temp'][when]))
        temp_feel_f = int(temperature.k2f(during_key['feels_like'][when]))
        sunrise = datetime.fromtimestamp(
            during_key['sunrise']).strftime("%I:%M %p")
        sunset = datetime.fromtimestamp(
            during_key['sunset']).strftime("%I:%M %p")
        if 'sunrise' in phrase or 'sun rise' in phrase or ('sun' in phrase and
                                                           'rise' in phrase):
            if datetime.strptime(datetime.today().strftime("%I:%M %p"), "%I:%M %p") >= \
                    datetime.strptime(sunrise, "%I:%M %p"):
                tense = "will be"
            else:
                tense = "was"
            speaker.speak(
                text=
                f"{tell} in {weather_location}, sunrise {tense} at {sunrise}.")
            return
        if 'sunset' in phrase or 'sun set' in phrase or ('sun' in phrase
                                                         and 'set' in phrase):
            if datetime.strptime(datetime.today().strftime("%I:%M %p"), "%I:%M %p") >= \
                    datetime.strptime(sunset, "%I:%M %p"):
                tense = "will be"
            else:
                tense = "was"
            speaker.speak(
                text=f"{tell} in {weather_location}, sunset {tense} at {sunset}"
            )
            return
        output = f"The weather in {weather_location} {tell} would be {temp_f}\N{DEGREE SIGN}F, with a high of " \
                 f"{high}, and a low of {low}. "
        if temp_feel_f != temp_f:
            output += f"But due to {condition} it will fee like it is {temp_feel_f}\N{DEGREE SIGN}F. "
        output += f"Sunrise at {sunrise}. Sunset at {sunset}. "
        if alerts and start_alert and end_alert:
            output += f'There is a weather alert for {alerts} between {start_alert} and {end_alert}'
        speaker.speak(text=output)
        return

    condition = response['current']['weather'][0]['description']
    high = int(temperature.k2f(arg=response['daily'][0]['temp']['max']))
    low = int(temperature.k2f(arg=response['daily'][0]['temp']['min']))
    temp_f = int(temperature.k2f(arg=response['current']['temp']))
    temp_feel_f = int(temperature.k2f(arg=response['current']['feels_like']))
    sunrise = datetime.fromtimestamp(
        response['daily'][0]['sunrise']).strftime("%I:%M %p")
    sunset = datetime.fromtimestamp(
        response['daily'][0]['sunset']).strftime("%I:%M %p")
    if phrase:
        if 'sunrise' in phrase or 'sun rise' in phrase or ('sun' in phrase and
                                                           'rise' in phrase):
            if datetime.strptime(datetime.today().strftime("%I:%M %p"), "%I:%M %p") >= \
                    datetime.strptime(sunrise, "%I:%M %p"):
                tense = "will be"
            else:
                tense = "was"
            speaker.speak(
                text=f"In {weather_location}, sunrise {tense} at {sunrise}.")
            return
        if 'sunset' in phrase or 'sun set' in phrase or ('sun' in phrase
                                                         and 'set' in phrase):
            if datetime.strptime(datetime.today().strftime("%I:%M %p"), "%I:%M %p") >= \
                    datetime.strptime(sunset, "%I:%M %p"):
                tense = "will be"
            else:
                tense = "was"
            speaker.speak(
                text=f"In {weather_location}, sunset {tense} at {sunset}")
            return
    if shared.called['time_travel']:
        if 'rain' in condition or 'showers' in condition:
            feeling = 'rainy'
            weather_suggest = 'You might need an umbrella" if you plan to head out.'
        elif temp_feel_f <= 40:
            feeling = 'freezing'
            weather_suggest = 'Perhaps" it is time for winter clothing.'
        elif 41 <= temp_feel_f <= 60:
            feeling = 'cool'
            weather_suggest = 'I think a lighter jacket would suffice" if you plan to head out.'
        elif 61 <= temp_feel_f <= 75:
            feeling = 'optimal'
            weather_suggest = 'It might be a perfect weather for a hike, or perhaps a walk.'
        elif 76 <= temp_feel_f <= 85:
            feeling = 'warm'
            weather_suggest = 'It is a perfect weather for some outdoor entertainment.'
        elif temp_feel_f > 85:
            feeling = 'hot'
            weather_suggest = "I would not recommend thick clothes today."
        else:
            feeling, weather_suggest = '', ''
        wind_speed = response['current']['wind_speed']
        if wind_speed > 10:
            output = f'The weather in {city} is {feeling} {temp_f}\N{DEGREE SIGN}, but due to the current wind ' \
                     f'conditions (which is {wind_speed} miles per hour), it feels like {temp_feel_f}\N{DEGREE SIGN}.' \
                     f' {weather_suggest}'
        else:
            output = f'The weather in {city} is {feeling} {temp_f}\N{DEGREE SIGN}, and it currently feels like ' \
                     f'{temp_feel_f}\N{DEGREE SIGN}. {weather_suggest}'
    else:
        output = f'The weather in {weather_location} is {temp_f}\N{DEGREE SIGN}F, with a high of {high}, and a low ' \
                 f'of {low}. It currently feels Like {temp_feel_f}\N{DEGREE SIGN}F, and the current condition is ' \
                 f'{condition}. Sunrise at {sunrise}. Sunset at {sunset}.'
    if 'alerts' in response:
        alerts = response['alerts'][0]['event']
        start_alert = datetime.fromtimestamp(
            response['alerts'][0]['start']).strftime("%I:%M %p")
        end_alert = datetime.fromtimestamp(
            response['alerts'][0]['end']).strftime("%I:%M %p")
    else:
        alerts, start_alert, end_alert = None, None, None
    if alerts and start_alert and end_alert:
        output += f' You have a weather alert for {alerts} between {start_alert} and {end_alert}'
    speaker.speak(text=output)