diff --git a/config.py b/config.py index 2904f4a..7b5df66 100644 --- a/config.py +++ b/config.py @@ -1,9 +1,10 @@ -#loc_city = "No longer supported" # Enter your city name (this is for the weather) -#loc_region = "No longer supported" # Enter either your state or country -weather_location = "" # Seems pretty flexible: city, state; major city name; zip code; city, country +#loc_city = "" # Enter your city name (this is for the weather) +#loc_region = "" # Enter either your state or country +weather_location = "" news_count = 2 # How many news stories Vector should read (max is 7 to 9) vector_mood = "normal" # Normal is the only mood at the moment -temperature = "farenheit" # Enter "farenheit" or "celsius" +temperature = "imperial" # Enter "imperial" or "metric" chattiness = 6 # Enter a number between "1" and "10". The number "5" is average. ("10" is VERY chatty.) This feature still needs work. sound_volume = 1 # Vector's sound effects between "1" and "5". (5 is very loud) -voice_volume = 2 # Vector's voice volume between "1" and "5". (5 is very loud) \ No newline at end of file +voice_volume = 3 # Vector's voice volume between "1" and "5". (5 is very loud) +news_feed = "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml" #I think you can use any rss feed for this \ No newline at end of file diff --git a/vectorator.py b/vectorator.py index c2f8be1..ec8a072 100644 --- a/vectorator.py +++ b/vectorator.py @@ -15,6 +15,7 @@ from anki_vector.user_intent import UserIntent, UserIntentEvent import apis import config +import sys, traceback # (I think these are called enums in Python... They relate to my dialogue.csv file) NAME = 0 @@ -204,10 +205,15 @@ def vector_react(arg): # This makes Vector talk by looking up dialogue in the dlg file def say(arg_name): - row_start = dic[arg_name] - row_end = row_start + int(dlg[row_start][LINES]) # Use row_start and LINES (from dialogue file) to figure out where the dialogue starts/stops - num_row = get_low(row_start,row_end-1) - to_say = dlg[num_row][MOOD] # Vector's default mood is "normal", eventually he will say different dialogue based on his mood + if arg_name in dic: + row_start = dic[arg_name] + print(row_start) + row_end = row_start + int(dlg[row_start][LINES]) # Use row_start and LINES (from dialogue file) to figure out where the dialogue starts/stops + num_row = get_low(row_start,row_end-1) + to_say = dlg[num_row][MOOD] # Vector's default mood is "normal", eventually he will say different dialogue based on his mood + else: + to_say = "" + if arg_name == "wake_word" : return # If wake_word then skip talking for a bit if arg_name == "news_intro": to_say = to_say + get_news() + get_weather("forecast") # if news then add to end of intro if arg_name == "joke_intro": to_say = to_say + get_joke() # if joke then add to end of intro @@ -215,6 +221,7 @@ def say(arg_name): if arg_name == "time_intro": to_say = to_say + get_time() # Randomly announce the time if arg_name == "random_weather": to_say = get_weather("random_weather") # Randomly announce a weather fact if arg_name == "stranger": to_say = to_say + get_pickupline() + if arg_name == "weather_forecast": to_say = get_weather("forecast") to_say = randomizer(to_say) # This replaces certain words with synonyms max_attempts = 15 # Had to add this after the last update. I'm having trouble getting control of Vector to speak @@ -227,7 +234,10 @@ def say(arg_name): robot.audio.set_master_volume(VOL[config.voice_volume]) # Change voice volume to config setting robot.behavior.say_text(to_say, duration_scalar=1.15) # I slow voice down slightly to make him easier to understand if arg_name == "joke_intro": - robot.anim.play_animation_trigger(random.choice(JOKE_ANIM)) # If a joke, play a random animation trigger + anim_trigger_names = robot.anim.anim_trigger_list + #robot.anim.play_animation_trigger(random.choice(JOKE_ANIM)) # If a joke, play a random animation trigger + robot.anim.play_animation_trigger( + random.choice(anim_trigger_names)) # If a joke, play a random animation trigger robot.conn.release_control() robot.audio.set_master_volume(VOL[config.sound_volume]) # Change sound effects volume back to config setting return @@ -272,12 +282,20 @@ def say_sleep(arg_name): robot.audio.set_master_volume(VOL[config.sound_volume]) robot.conn.release_control() + +def average(number1, number2): + return (number1 + number2) / 2 + # An API call that allows Vector to deliver a weather forecast (it's not always accurate, in my experience) def get_weather(var): #10/23/2019 JDR new API endpoint (and terms) try: #location can be city, state; city, country; zip code. - url = f"http://api.weatherstack.com/current?access_key={apis.api_weather}&query={config.weather_location}&units={config.temperature[0]}" + + if var == "forecast": + url = f"http://api.openweathermap.org/data/2.5/forecast?APPID={apis.api_weather}&q={config.weather_location}&units={config.temperature}" + else: + url = f"http://api.openweathermap.org/data/2.5/weather?APPID={apis.api_weather}&q={config.weather_location}&units={config.temperature}" print(url) req = urllib.request.Request( url, @@ -286,25 +304,36 @@ def get_weather(var): ) data = urllib.request.urlopen(req).read() output = json.loads(data) - #10/23/2019 JDR free api, no forecast (weather.gov for US?) - #forecast_condition = output["forecast"]["forecastday"][0]["day"]["condition"]["text"] - #10/23/2019 JDR new API object - current_condition = output["current"]["weather_descriptions"] - #forecast_avghumidity = output["forecast"]["forecastday"][0]["day"]["avghumidity"] - current_humidity = output["current"]["humidity"] - - weather_name = output["location"]["name"] - weather_region = output["location"]["region"] - - #New API, specify the units in the request - current_temp_feelslike = output["current"]["feelslike"] - current_temp = output["current"]["temperature"] - current_wind = output["current"]["wind_speed"] - - if config.temperature == "farenheit": + + print(data) + + if var == "forecast": + section =output["list"][0] + forecast_condition = section["weather"][0]["description"] + forecast_humidity = section["main"]["humidity"] + forecast_temp = output["list"][0]["main"]["temp"] + forecast_temp_high = int(round(section["main"]["temp_min"])) + forecast_temp_low = int(round(section["main"]["temp_max"])) + forecast_temp_avg = int(round(average(forecast_temp_high, forecast_temp_low))) + forecast_wind = int(round(section["wind"]["speed"])) + else: + #10/23/2019 JDR free api, no forecast (weather.gov for US?) + #forecast_condition = output["forecast"]["forecastday"][0]["day"]["condition"]["text"] + #10/23/2019 JDR new API object + current_condition = output["weather"][0]["description"] + #forecast_avghumidity = output["forecast"]["forecastday"][0]["day"]["avghumidity"] + current_humidity = output["main"]["humidity"] + + #weather_name = output["location"]["name"] + #weather_region = output["location"]["region"] + + #New API, specify the units in the request + #current_temp_feelslike = output["current"]["feelslike"] + current_temp = int(round(average(output["main"]["temp_min"], output["main"]["temp_max"]))) + current_wind = output["wind"]["speed"] + + if config.temperature == "imperial": #forecast_temp_avg = output["forecast"]["forecastday"][0]["day"]["avgtemp_f"] - #forecast_temp_high = output["forecast"]["forecastday"][0]["day"]["maxtemp_f"] - #forecast_temp_low = output["forecast"]["forecastday"][0]["day"]["mintemp_f"] #forecast_wind = output["forecast"]["forecastday"][0]["day"]["maxwind_mph"] wind_speed = " miles per hour" else: @@ -315,29 +344,31 @@ def get_weather(var): wind_speed = " kilometers per hour" # In the morning, Vector tells the news and weather when he sees a face - # if var == "forecast": - # weather = [] - # weather.append(f". And now for some weather. Today in {config.loc_city} {config.loc_region}, it will be {forecast_condition}, with a temperature of {forecast_temp_high} degrees, and wind speeds around {forecast_wind}{wind_speed}. Right now, it is {current_temp} degrees.") - # weather.append(f". Right now in {config.loc_city} {config.loc_region}, it is {current_temp} degrees and {current_condition}. Later today, it will be {forecast_condition}, with a high of {forecast_temp_high} degrees and a low of {forecast_temp_low} degrees.") - # weather.append(f". Here's your local weather. The temperature in {config.loc_city} {config.loc_region} right now, is {current_temp} degrees. The high today will be {forecast_temp_high} degrees, and look for a low of around {forecast_temp_low}. Winds will be {forecast_wind}{wind_speed}.") - # weather.append(f". Moving to the weather. It is currently {current_condition} in {config.loc_city} {config.loc_region}. Later today it will be {forecast_condition}, with an average temperature of {forecast_temp_avg} degrees, and wind speeds around {forecast_wind}{wind_speed}.") - # return(random.choice(weather)) + if var == "forecast": + weather = [] + weather.append(f". And now for some weather. Today, it will be {forecast_condition}, with a temperature of {forecast_temp_high} degrees, and wind speeds around {forecast_wind}{wind_speed}.") + weather.append(f". Later today, it will be {forecast_condition}, with a high of {forecast_temp_high} degrees and a low of {forecast_temp_low} degrees.") + weather.append(f". Here's your local weather. The high today will be {forecast_temp_high} degrees, and look for a low of around {forecast_temp_low}. Winds will be {forecast_wind}{wind_speed}.") + weather.append(f". Later today it will be {forecast_condition}, with an average temperature of {forecast_temp_avg} degrees, and wind speeds around {forecast_wind}{wind_speed}.") + return(random.choice(weather)) # At random times, Vector will see a face and announce something about the weather - # if var == "random_weather": - rnd_weather = [] - if {current_temp} != {current_temp_feelslike}: - rnd_weather.append(f"The current temperature is {current_temp} degrees, but it feels like {current_temp_feelslike} degrees.") - rnd_weather.append(f"Right now, the temperature is {current_temp} degrees.") - if current_wind < 15: - rnd_weather.append(f"Right now, it is a relatively calm {current_temp} degrees, with winds at {current_wind}{wind_speed}.") - else: - rnd_weather.append(f"Right now, it is a blustery {current_temp} degrees, with winds at {current_wind}{wind_speed}.") - rnd_weather.append(f"At this moment, the weather is {current_condition}.") - rnd_weather.append(f"Hello. It is currently {current_temp} degrees. The humidity is {current_humidity} percent.") + if var == "random_weather": + rnd_weather = [] + #if {current_temp} != {current_temp_feelslike}: + # rnd_weather.append(f"The current temperature is {current_temp} degrees, but it feels like {current_temp_feelslike} degrees.") + rnd_weather.append(f"Right now, the temperature is {current_temp} degrees.") + + if current_wind < 15: + rnd_weather.append(f"Right now, it is a relatively calm {current_temp} degrees, with winds at {current_wind}{wind_speed}.") + else: + rnd_weather.append(f"Right now, it is a blustery {current_temp} degrees, with winds at {current_wind}{wind_speed}.") + rnd_weather.append(f"At this moment, the weather is {current_condition}.") + rnd_weather.append(f"Hello. It is currently {current_temp} degrees. The humidity is {current_humidity} percent.") + + except Exception as inst: + print(traceback.format_exc()) - except: - print("Unexpected weather error:", sys.exc_info()[0]) rnd_weather.append("I'm more of an indoor robot.") rnd_weather.append("I have no idea what it is like out there.") rnd_weather.append("I'm a robot, not a weather forecaster.") @@ -352,7 +383,7 @@ def get_news(): bridge = [". And in other news. ", ". In OTHER news... ", ". Taking a look at other news. ", ". Here is another news item. ", ". Here is an interesting story. "] news = "" news_count = config.news_count - feed = feedparser.parse("https://www.cbsnews.com/latest/rss/world") + feed = feedparser.parse(config.news_feed) for post in feed.entries: news = news + post.description say_count += 1 @@ -410,13 +441,19 @@ def on_wake_word(robot, event_type, event): "imperative_come", "imperative_lookatme", "weather_response"] if j['type'] == "weather_response": - #allow vector to do his built in weather - time.sleep(10) - say("random_weather") + if j["isForecast"] == "true": + print("weather_forecast") + say("weather_forecast") + else: + # allow vector to do his built in weather + time.sleep(10) + say("random_weather") else: if j['type'] in valid_response: print("valid response") - reaction78u = random.choices(["joke_intro", "fact_intro", "time_intro", "random_weather", "last_saw_name"]) + #took out the time, you can already ask for that. + #taking out last_saw_name until I check to see if he has seen a face he knows. + reaction = random.choices(["joke_intro", "fact_intro", "random_weather"]) print(reaction) say(reaction[0]) @@ -524,9 +561,10 @@ def on_cube_detected(robot, event_type, event): if not robot.status.is_on_charger: battery_state = robot.get_battery_state() - if battery_state.battery_volts < 3.6: + if battery_state.battery_volts <= 3.63: # <3.61 was too low + print(battery_state.battery_volts) robot.behavior.say_text("I need to find my charger soon.") - time.sleep(30) + time.sleep(90) #if battery_state.battery_level < 2: #robot.behavior.say_text("My battery level is low.")