More Location integration for #487
For the Weather Skill: * When talking about the current city, the city name is generally not spoken (more natural) * A "pretty" name of just the city is used instead of the complete name * Works around the recurring issue with OWM where they report bad min/max temps (same as the current temp) * Changed "Location is not valid" to "I don't know that location" (people don't say "not valid") For the Time Skill: * The timezone is extracted from the device location setting * Time responses are more varied and shorter This change adds MycroftSkill.location_pretty and MycroftSkill.location_timezone properties.pull/497/head
parent
c3070beb7b
commit
acfdff416b
|
@ -178,8 +178,27 @@ class MycroftSkill(object):
|
|||
|
||||
@property
|
||||
def location(self):
|
||||
""" Get the JSON data struction holding location information. """
|
||||
# TODO: Allow Enclosure to override this for devices that
|
||||
# contain a GPS.
|
||||
return self.config_core.get('location')
|
||||
|
||||
@property
|
||||
def location_pretty(self):
|
||||
""" Get a more 'human' version of the location as a string. """
|
||||
loc = self.location
|
||||
if type(loc) is dict and loc["city"]:
|
||||
return loc["city"]["name"]
|
||||
return None
|
||||
|
||||
@property
|
||||
def location_timezone(self):
|
||||
""" Get the timezone code, such as 'America/Los_Angeles' """
|
||||
loc = self.location
|
||||
if type(loc) is dict and loc["timezone"]:
|
||||
return loc["timezone"]["code"]
|
||||
return None
|
||||
|
||||
@property
|
||||
def lang(self):
|
||||
return self.config_core.get('lang')
|
||||
|
|
|
@ -50,22 +50,29 @@ class TimeSkill(MycroftSkill):
|
|||
|
||||
def get_timezone(self, locale):
|
||||
try:
|
||||
# This handles common city names, like "Dallas" or "Paris"
|
||||
return timezone(self.astral[locale].timezone)
|
||||
except:
|
||||
try:
|
||||
# This handles codes like "America/Los_Angeles"
|
||||
return timezone(locale)
|
||||
except:
|
||||
return None
|
||||
|
||||
# This method only handles localtime, for other timezones the task falls
|
||||
# to Wolfram.
|
||||
def handle_intent(self, message):
|
||||
location = message.data.get("Location")
|
||||
now = datetime.datetime.now(timezone('UTC'))
|
||||
tz = tzlocal.get_localzone()
|
||||
location = message.data.get("Location") # optional parameter
|
||||
nowUTC = datetime.datetime.now(timezone('UTC'))
|
||||
|
||||
tz = self.get_timezone(self.location_timezone)
|
||||
if location:
|
||||
tz = self.get_timezone(location)
|
||||
|
||||
if not tz:
|
||||
self.speak_dialog("time.tz.not.found", {"location": location})
|
||||
return
|
||||
time = now.astimezone(tz).strftime(self.format)
|
||||
|
||||
# Convert UTC to appropriate timezone and format
|
||||
time = nowUTC.astimezone(tz).strftime(self.format)
|
||||
self.speak_dialog("time.current", {"time": time})
|
||||
|
||||
def stop(self):
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
It is currently {{time}}
|
||||
{{time}}
|
||||
It is {{time}}
|
||||
{{time}}
|
||||
It's {{time}}
|
||||
Currently {{time}}
|
||||
|
|
|
@ -129,15 +129,31 @@ class WeatherSkill(MycroftSkill):
|
|||
|
||||
def handle_current_intent(self, message):
|
||||
try:
|
||||
location = self.get_location(message)
|
||||
location, pretty_location = self.get_location(message)
|
||||
|
||||
weather = self.owm.weather_at_place(location).get_weather()
|
||||
data = self.__build_data_condition(location, weather)
|
||||
data = self.__build_data_condition(pretty_location, weather)
|
||||
|
||||
# BUG: OWM is commonly reporting incorrect high/low data in the
|
||||
# "current" request. So grab that from the forecast API call.
|
||||
weather_forecast = self.owm.three_hours_forecast(
|
||||
location).get_forecast().get_weathers()[0]
|
||||
data_forecast = self.__build_data_condition(pretty_location,
|
||||
weather_forecast)
|
||||
data["temp_min"] = data_forecast["temp_min"]
|
||||
data["temp_max"] = data_forecast["temp_max"]
|
||||
|
||||
weather_code = str(weather.get_weather_icon_name())
|
||||
img_code = self.CODES[weather_code]
|
||||
temp = data['temp_current']
|
||||
self.enclosure.deactivate_mouth_events()
|
||||
self.enclosure.weather_display(img_code, temp)
|
||||
self.speak_dialog('current.weather', data)
|
||||
|
||||
dialog_name = "current"
|
||||
if pretty_location == self.location_pretty:
|
||||
dialog_name += ".local"
|
||||
self.speak_dialog(dialog_name+".weather", data)
|
||||
|
||||
time.sleep(5)
|
||||
self.enclosure.activate_mouth_events()
|
||||
except HTTPError as e:
|
||||
|
@ -147,15 +163,18 @@ class WeatherSkill(MycroftSkill):
|
|||
|
||||
def handle_next_hour_intent(self, message):
|
||||
try:
|
||||
location = self.get_location(message)
|
||||
location, pretty_location = self.get_location(message)
|
||||
weather = self.owm.three_hours_forecast(
|
||||
location).get_forecast().get_weathers()[0]
|
||||
data = self.__build_data_condition(location, weather)
|
||||
data = self.__build_data_condition(pretty_location, weather)
|
||||
weather_code = str(weather.get_weather_icon_name())
|
||||
img_code = self.CODES[weather_code]
|
||||
temp = data['temp_current']
|
||||
self.enclosure.deactivate_mouth_events()
|
||||
self.enclosure.weather_display(img_code, temp)
|
||||
if pretty_location == self.location_pretty:
|
||||
self.speak_dialog('hour.weather', data)
|
||||
else:
|
||||
self.speak_dialog('hour.weather', data)
|
||||
time.sleep(5)
|
||||
self.enclosure.activate_mouth_events()
|
||||
|
@ -166,16 +185,19 @@ class WeatherSkill(MycroftSkill):
|
|||
|
||||
def handle_next_day_intent(self, message):
|
||||
try:
|
||||
location = self.get_location(message)
|
||||
location, pretty_location = self.get_location(message)
|
||||
weather = self.owm.daily_forecast(
|
||||
location).get_forecast().get_weathers()[1]
|
||||
data = self.__build_data_condition(
|
||||
location, weather, 'day', 'min', 'max')
|
||||
pretty_location, weather, 'day', 'min', 'max')
|
||||
weather_code = str(weather.get_weather_icon_name())
|
||||
img_code = self.CODES[weather_code]
|
||||
temp = data['temp_current']
|
||||
self.enclosure.deactivate_mouth_events()
|
||||
self.enclosure.weather_display(img_code, temp)
|
||||
if pretty_location == self.location_pretty:
|
||||
self.speak_dialog('tomorrow.local.weather', data)
|
||||
else:
|
||||
self.speak_dialog('tomorrow.weather', data)
|
||||
time.sleep(5)
|
||||
self.enclosure.activate_mouth_events()
|
||||
|
@ -186,25 +208,28 @@ class WeatherSkill(MycroftSkill):
|
|||
|
||||
def get_location(self, message):
|
||||
try:
|
||||
location = message.data.get("Location", self.location)
|
||||
location = message.data.get("Location", None)
|
||||
if location:
|
||||
return location, location
|
||||
|
||||
location = self.location
|
||||
if type(location) is dict:
|
||||
city = location["city"]
|
||||
state = city["state"]
|
||||
return city["name"] + ", " + state["name"] + ", " + \
|
||||
state["country"]["name"]
|
||||
else:
|
||||
return location
|
||||
state["country"]["name"], self.location_pretty
|
||||
|
||||
return None
|
||||
except:
|
||||
self.speak_dialog("location.not.found")
|
||||
raise ValueError("Location not found")
|
||||
|
||||
def __build_data_condition(
|
||||
self, location, weather, temp='temp', temp_min='temp_min',
|
||||
self, location_pretty, weather, temp='temp', temp_min='temp_min',
|
||||
temp_max='temp_max'):
|
||||
if type(location) is dict:
|
||||
location = location["city"]["name"]
|
||||
|
||||
data = {
|
||||
'location': location,
|
||||
'location': location_pretty,
|
||||
'scale': self.temperature,
|
||||
'condition': weather.get_detailed_status(),
|
||||
'temp_current': self.__get_temperature(weather, temp),
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
It's currently {{condition}} and {{temp_current}} degrees {{scale}}. Today's forecast is for a high of {{temp_max}} and a low of {{temp_min}}.
|
||||
Right now, it's {{condition}} and {{temp_current}} degrees, for a high of {{temp_max}} and a low of {{temp_min}}.
|
||||
With a high of {{temp_max}} and a low of {{temp_min}}, {{location}} has {{condition}} and is currently {{temp_current}} degrees.
|
|
@ -0,0 +1,2 @@
|
|||
In the next few hours, it will be {{condition}}, with a high of {{temp_max}} and a low of {{temp_min}}
|
||||
The will be a high of {{temp_max}} and a low of {{temp_min}}, with {{condition}} conditions in the following hours
|
|
@ -1,3 +1,3 @@
|
|||
I could not find a valid location
|
||||
Location is not valid
|
||||
I could not find a that location
|
||||
I don't know that location
|
||||
Location not found
|
|
@ -0,0 +1,2 @@
|
|||
Tomorrow it will be {{condition}}, with a high of {{temp_max}} and a low of {{temp_min}}
|
||||
Tomorrow there will have a high of {{temp_max}} and a low of {{temp_min}}, with {{condition}} conditions
|
Loading…
Reference in New Issue