Merge branch 'prerelease-0.8.1'

Preparing master for the 0.8.1 release
pull/477/head
Steve Penrod 2017-01-24 17:38:16 -06:00
commit 2d3846fd42
17 changed files with 94 additions and 29 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
sudo pacman -S \
sudo pacman -S --needed \
git \
python2 \
python2-pip \

View File

@ -27,6 +27,7 @@ setup(
'mycroft-audio-test=mycroft.util.audio_test:main',
'mycroft-enclosure-client=mycroft.client.enclosure.main:main',
'mycroft-wifi-setup-client=mycroft.client.wifisetup.main:main',
'mycroft-skill-container=mycroft.skills.container:main',
'mycroft-cli-client=mycroft.client.text.main:main'
]
}

View File

@ -37,7 +37,7 @@ class Api(object):
query = self.build_query(params)
url = self.build_url(params)
response = requests.request(method, url, headers=headers, params=query,
data=data, json=json)
data=data, json=json, timeout=(3.05, 15))
return self.get_response(response)
def request(self, params):

View File

@ -80,10 +80,22 @@ def handle_multi_utterance_intent_failure(event):
def handle_speak(event):
utterance = event.data['utterance']
chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s', utterance)
for chunk in chunks:
mute_and_speak(chunk)
# This is a bit of a hack for Picroft. The analog audio on a Pi blocks
# for 30 seconds fairly often, so we don't want to break on periods
# (decreasing the chance of encountering the block). But we will
# keep the split for non-Picroft installs since it give user feedback
# faster on longer phrases.
#
# TODO: Remove or make an option? This is really a hack, anyway,
# so we likely will want to get rid of this when not running on Mimic
if not config.get('enclosure', {}).get('platform') == "picroft":
chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s',
utterance)
for chunk in chunks:
mute_and_speak(chunk)
else:
mute_and_speak(utterance)
def handle_sleep(event):
loop.sleep()

View File

@ -374,7 +374,7 @@ class WiFi:
if "(incomplete)" in o:
# ping the IP to get the ARP table entry reloaded
ip_disconnected = o.split(" ")[0]
cli_no_output('/bin/ping', '-c', '1', '-W', 3,
cli_no_output('/bin/ping', '-c', '1', '-W', '3',
ip_disconnected)
else:
return True # something on subnet is connected!
@ -520,7 +520,7 @@ def main():
try:
wifi.run()
except Exception as e:
print (e)
print(e)
finally:
sys.exit()

View File

@ -54,7 +54,8 @@ class ConfigurationSkill(ScheduledSkill):
self.update()
except HTTPError as e:
if e.response.status_code == 401:
self.log.warn("Impossible to update configuration because device isn't paired")
self.log.warn("Impossible to update configuration because "
"device isn't paired")
self.schedule()
def update(self):

View File

@ -37,7 +37,9 @@ __author__ = 'seanfitz'
PRIMARY_SKILLS = ['intent', 'wake']
BLACKLISTED_SKILLS = ["send_sms", "media"]
SKILLS_BASEDIR = dirname(__file__)
THIRD_PARTY_SKILLS_DIR = "/opt/mycroft/skills"
THIRD_PARTY_SKILLS_DIR = ["/opt/mycroft/third_party", "/opt/mycroft/skills"]
# Note: /opt/mycroft/skills is recommended, /opt/mycroft/third_party
# is for backwards compatibility
MainModule = '__init__'
@ -117,6 +119,14 @@ def get_skills(skills_folder):
possible_skills = os.listdir(skills_folder)
for i in possible_skills:
location = join(skills_folder, i)
if (isdir(location) and
not MainModule + ".py" in os.listdir(location)):
for j in os.listdir(location):
name = join(location, j)
if (not isdir(name) or
not MainModule + ".py" in os.listdir(name)):
continue
skills.append(create_skill_descriptor(name))
if (not isdir(location) or
not MainModule + ".py" in os.listdir(location)):
continue
@ -132,15 +142,22 @@ def create_skill_descriptor(skill_folder):
def load_skills(emitter, skills_root=SKILLS_BASEDIR):
skill_list = []
skills = get_skills(skills_root)
for skill in skills:
if skill['name'] in PRIMARY_SKILLS:
load_skill(skill, emitter)
skill_list.append(load_skill(skill, emitter))
for skill in skills:
if (skill['name'] not in PRIMARY_SKILLS and
skill['name'] not in BLACKLISTED_SKILLS):
load_skill(skill, emitter)
skill['name'] not in BLACKLISTED_SKILLS):
skill_list.append(load_skill(skill, emitter))
return skill_list
def unload_skills(skills):
for s in skills:
s.cleanup()
class MycroftSkill(object):
@ -252,3 +269,7 @@ class MycroftSkill(object):
def is_stop(self):
passed_time = time.time() - self.stop_time
return passed_time < self.stop_threshold
def cleanup(self):
""" Clean up running threads, etc. """
pass

View File

@ -41,8 +41,9 @@ def load_skills_callback():
except AttributeError as e:
logger.warning(e.message)
if exists(THIRD_PARTY_SKILLS_DIR):
load_skills(ws, THIRD_PARTY_SKILLS_DIR)
for loc in THIRD_PARTY_SKILLS_DIR:
if exists(loc):
load_skills(client, loc)
if ini_third_party_skills_dir and exists(ini_third_party_skills_dir):
load_skills(ws, ini_third_party_skills_dir)

View File

@ -85,7 +85,9 @@ class PairingSkill(MycroftSkill):
return device is not None
def speak_code(self):
data = {"code": '. '.join(self.data.get("code"))}
code = self.data.get("code")
self.log.info("Pairing code: " + code)
data = {"code": '. '.join(code).replace("0", "zero")}
self.speak_dialog("pairing.code", data)
def stop(self):

View File

@ -113,6 +113,11 @@ class ScheduledSkill(MycroftSkill):
def notify(self, timestamp):
pass
def cleanup(self):
""" Cancel timer making the skill ready for shutdown """
if self.timer:
self.timer.cancel()
class ScheduledCRUDSkill(ScheduledSkill):
"""

View File

@ -179,7 +179,7 @@ class WolframAlphaSkill(MycroftSkill):
if len(others) > 0:
self.speak_dialog('others.found',
data={'utterance': utterance, 'alternative':
others[0]})
others[0]})
else:
self.speak_dialog("not.understood", data={'phrase': phrase})

View File

@ -39,7 +39,7 @@ class TTS(object):
def __init__(self, lang, voice, validator):
super(TTS, self).__init__()
self.lang = lang
self.lang = lang or 'en-us'
self.voice = voice
self.filename = '/tmp/tts.wav'
self.validator = validator

View File

@ -19,7 +19,7 @@
from gtts import gTTS
from mycroft.tts import TTS, TTSValidator
from mycroft.util import play_wav
from mycroft.util import play_mp3
__author__ = 'jdorleans'
@ -31,7 +31,8 @@ class GoogleTTS(TTS):
def execute(self, sentence):
tts = gTTS(sentence, self.lang)
tts.save(self.filename)
play_wav(self.filename).communicate()
p = play_mp3(self.filename)
p.communicate() # Wait for termination
class GoogleTTSValidator(TTSValidator):

View File

@ -22,6 +22,16 @@ from mycroft.util.log import getLogger
__author__ = 'augustnmonteiro'
# The following lines are replaced during the release process.
# START_VERSION_BLOCK
CORE_VERSION_MAJOR = 0
CORE_VERSION_MINOR = 8
CORE_VERSION_BUILD = 1
# END_VERSION_BLOCK
CORE_VERSION_STR = (str(CORE_VERSION_MAJOR) + "." +
str(CORE_VERSION_MINOR) + "." +
str(CORE_VERSION_BUILD))
LOG = getLogger(__name__)
@ -30,10 +40,12 @@ class VersionManager(object):
@staticmethod
def get():
if exists(VersionManager.__location) and isfile(VersionManager.__location):
if (exists(VersionManager.__location) and
isfile(VersionManager.__location)):
try:
with open(VersionManager.__location) as f:
return json.load(f)
except:
LOG.error("Failed to load version from '%s'" % VersionManager.__location)
LOG.error("Failed to load version from '%s'"
% VersionManager.__location)
return {"coreVersion": None, "enclosureVersion": None}

View File

@ -2,11 +2,12 @@ shortuuid==0.4.3
pystache==0.5.4
configobj==5.0.6
wikipedia==1.4.0
requests==2.8.1
requests==2.12.5
pyOpenSSL==16.0.0
ndg-httpsclient==0.4.0
pyasn1==0.1.9
gTTS==1.0.7
gTTS==1.1.7
gTTS-token==1.1.1
backports.ssl-match-hostname==3.4.0.2
certifi==2016.2.28
PyAudio==0.2.8
@ -38,4 +39,4 @@ wifi==0.3.8
pyroute2==0.4.5
urllib5==5.0.0
pyric==0.1.6
inflection==0.3.1
inflection==0.3.1

View File

@ -50,8 +50,13 @@ class IntentTestSequence(unittest.TestCase):
__metaclass__ = IntentTestSequenceMeta
def setUp(self):
self.emitter = MockSkillsLoader(
os.path.join(PROJECT_ROOT, 'mycroft', 'skills')).load_skills()
self.loader = MockSkillsLoader(
os.path.join(PROJECT_ROOT, 'mycroft', 'skills'))
self.emitter = self.loader.load_skills()
def tearDown(self):
self.loader.unload_skills()
if __name__ == '__main__':
unittest.main()

View File

@ -3,7 +3,7 @@ import json
from pyee import EventEmitter
from mycroft.messagebus.message import Message
from mycroft.skills.core import load_skills
from mycroft.skills.core import load_skills, unload_skills
__author__ = 'seanfitz'
@ -31,9 +31,12 @@ class MockSkillsLoader(object):
self.emitter = RegistrationOnlyEmitter()
def load_skills(self):
load_skills(self.emitter, self.skills_root)
self.skills = load_skills(self.emitter, self.skills_root)
return self.emitter.emitter # kick out the underlying emitter
def unload_skills(self):
unload_skills(self.skills)
class SkillTest(object):
def __init__(self, skill, example, emitter):