2017-10-04 06:28:44 +00:00
|
|
|
# Copyright 2017 Mycroft AI Inc.
|
2016-05-26 16:16:13 +00:00
|
|
|
#
|
2017-10-04 06:28:44 +00:00
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
2016-05-26 16:16:13 +00:00
|
|
|
#
|
2017-10-04 06:28:44 +00:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2016-05-26 16:16:13 +00:00
|
|
|
#
|
2017-10-04 06:28:44 +00:00
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
2016-05-26 16:16:13 +00:00
|
|
|
#
|
2017-02-21 05:43:50 +00:00
|
|
|
import time
|
2018-08-16 16:25:02 +00:00
|
|
|
from threading import Timer
|
2017-10-13 07:21:58 +00:00
|
|
|
import mycroft.lock
|
2018-05-08 00:24:26 +00:00
|
|
|
from mycroft import dialog
|
2018-03-27 23:51:30 +00:00
|
|
|
from mycroft.api import is_paired, BackendDown
|
2018-04-03 14:50:53 +00:00
|
|
|
from mycroft.client.enclosure.api import EnclosureAPI
|
2017-09-23 12:13:50 +00:00
|
|
|
from mycroft.configuration import Configuration
|
2016-05-20 14:16:01 +00:00
|
|
|
from mycroft.messagebus.client.ws import WebsocketClient
|
2017-04-06 23:08:23 +00:00
|
|
|
from mycroft.messagebus.message import Message
|
2018-04-03 14:50:53 +00:00
|
|
|
from mycroft.util import (
|
|
|
|
connected, wait_while_speaking, reset_sigint_handler,
|
|
|
|
create_echo_function, create_daemon, wait_for_exit_signal
|
|
|
|
)
|
2018-08-16 16:25:02 +00:00
|
|
|
|
|
|
|
from .skill_manager import SkillManager
|
|
|
|
from .core import FallbackSkill
|
|
|
|
from .event_scheduler import EventScheduler
|
|
|
|
from .intent_service import IntentService
|
|
|
|
from .padatious_service import PadatiousService
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2018-08-22 01:50:50 +00:00
|
|
|
bus = None # Mycroft messagebus reference, see "mycroft.messagebus"
|
2017-08-30 17:19:06 +00:00
|
|
|
event_scheduler = None
|
2017-10-13 07:21:58 +00:00
|
|
|
skill_manager = None
|
2017-09-11 11:11:56 +00:00
|
|
|
|
2018-01-18 03:05:51 +00:00
|
|
|
# Remember "now" at startup. Used to detect clock changes.
|
2018-06-11 14:05:50 +00:00
|
|
|
start_ticks = time.monotonic()
|
2018-01-18 03:05:51 +00:00
|
|
|
start_clock = time.time()
|
|
|
|
|
2017-03-14 16:12:34 +00:00
|
|
|
|
2017-02-21 05:43:50 +00:00
|
|
|
def connect():
|
2018-08-22 01:50:50 +00:00
|
|
|
global bus
|
|
|
|
bus.run_forever()
|
2017-02-21 05:43:50 +00:00
|
|
|
|
|
|
|
|
2017-08-18 15:15:55 +00:00
|
|
|
def _starting_up():
|
|
|
|
"""
|
|
|
|
Start loading skills.
|
|
|
|
|
|
|
|
Starts
|
2017-10-13 07:21:58 +00:00
|
|
|
- SkillManager to load/reloading of skills when needed
|
2017-08-18 15:15:55 +00:00
|
|
|
- a timer to check for internet connection
|
|
|
|
- adapt intent service
|
|
|
|
- padatious intent service
|
|
|
|
"""
|
2018-08-22 01:50:50 +00:00
|
|
|
global bus, skill_manager, event_scheduler
|
2017-02-21 05:43:50 +00:00
|
|
|
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.on('intent_failure', FallbackSkill.make_intent_failure_handler(bus))
|
2017-06-16 21:40:12 +00:00
|
|
|
|
2017-04-14 08:53:29 +00:00
|
|
|
# Create the Intent manager, which converts utterances to intents
|
|
|
|
# This is the heart of the voice invoked skill system
|
2017-05-31 19:53:21 +00:00
|
|
|
|
2018-08-22 01:50:50 +00:00
|
|
|
service = IntentService(bus)
|
|
|
|
PadatiousService(bus, service)
|
|
|
|
event_scheduler = EventScheduler(bus)
|
2017-10-13 07:21:58 +00:00
|
|
|
|
2017-04-14 08:53:29 +00:00
|
|
|
# Create a thread that monitors the loaded skills, looking for updates
|
2018-08-22 01:50:50 +00:00
|
|
|
skill_manager = SkillManager(bus)
|
2017-10-13 07:21:58 +00:00
|
|
|
skill_manager.daemon = True
|
2017-09-04 13:30:30 +00:00
|
|
|
# Wait until skills have been loaded once before starting to check
|
|
|
|
# network connection
|
2018-05-08 00:24:26 +00:00
|
|
|
skill_manager.load_priority()
|
|
|
|
skill_manager.start()
|
2017-09-04 13:30:30 +00:00
|
|
|
check_connection()
|
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2017-04-25 22:18:43 +00:00
|
|
|
def check_connection():
|
2017-08-21 15:05:03 +00:00
|
|
|
"""
|
|
|
|
Check for network connection. If not paired trigger pairing.
|
|
|
|
Runs as a Timer every second until connection is detected.
|
|
|
|
"""
|
2017-04-25 22:18:43 +00:00
|
|
|
if connected():
|
2018-08-22 01:50:50 +00:00
|
|
|
enclosure = EnclosureAPI(bus)
|
2018-01-18 03:05:51 +00:00
|
|
|
|
2018-01-18 20:44:53 +00:00
|
|
|
if is_paired():
|
|
|
|
# Skip the sync message when unpaired because the prompt to go to
|
|
|
|
# home.mycrof.ai will be displayed by the pairing skill
|
2018-03-27 23:51:30 +00:00
|
|
|
enclosure.mouth_text(dialog.get("message_synching.clock"))
|
2018-02-25 19:53:04 +00:00
|
|
|
|
2018-01-18 03:05:51 +00:00
|
|
|
# Force a sync of the local clock with the internet
|
2018-02-25 19:53:04 +00:00
|
|
|
config = Configuration.get()
|
|
|
|
platform = config['enclosure'].get("platform", "unknown")
|
|
|
|
if platform in ['mycroft_mark_1', 'picroft']:
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message("system.ntp.sync"))
|
2018-03-27 23:51:30 +00:00
|
|
|
time.sleep(15) # TODO: Generate/listen for a message response...
|
2018-01-18 03:05:51 +00:00
|
|
|
|
|
|
|
# Check if the time skewed significantly. If so, reboot
|
2018-06-11 14:05:50 +00:00
|
|
|
skew = abs((time.monotonic() - start_ticks) -
|
2018-01-18 03:05:51 +00:00
|
|
|
(time.time() - start_clock))
|
2018-02-27 22:22:40 +00:00
|
|
|
if skew > 60 * 60:
|
2018-01-18 03:05:51 +00:00
|
|
|
# Time moved by over an hour in the NTP sync. Force a reboot to
|
|
|
|
# prevent weird things from occcurring due to the 'time warp'.
|
|
|
|
#
|
2018-04-03 14:50:53 +00:00
|
|
|
data = {'utterance': dialog.get("time.changed.reboot")}
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message("speak", data))
|
2018-01-18 03:05:51 +00:00
|
|
|
wait_while_speaking()
|
|
|
|
|
|
|
|
# provide visual indicators of the reboot
|
2018-03-27 23:51:30 +00:00
|
|
|
enclosure.mouth_text(dialog.get("message_rebooting"))
|
2018-01-18 03:05:51 +00:00
|
|
|
enclosure.eyes_color(70, 65, 69) # soft gray
|
2018-01-18 20:44:53 +00:00
|
|
|
enclosure.eyes_spin()
|
2018-01-18 03:05:51 +00:00
|
|
|
|
|
|
|
# give the system time to finish processing enclosure messages
|
2018-01-18 20:44:53 +00:00
|
|
|
time.sleep(1.0)
|
2018-01-18 03:05:51 +00:00
|
|
|
|
|
|
|
# reboot
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message("system.reboot"))
|
2018-01-18 03:05:51 +00:00
|
|
|
return
|
2018-02-15 08:43:06 +00:00
|
|
|
else:
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message("enclosure.mouth.reset"))
|
2018-02-15 08:43:06 +00:00
|
|
|
time.sleep(0.5)
|
2018-01-18 03:05:51 +00:00
|
|
|
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message('mycroft.internet.connected'))
|
2017-06-07 10:00:29 +00:00
|
|
|
# check for pairing, if not automatically start pairing
|
2018-03-27 23:51:30 +00:00
|
|
|
try:
|
|
|
|
if not is_paired(ignore_errors=False):
|
|
|
|
payload = {
|
|
|
|
'utterances': ["pair my device"],
|
|
|
|
'lang': "en-us"
|
|
|
|
}
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message("recognizer_loop:utterance", payload))
|
2018-03-27 23:51:30 +00:00
|
|
|
else:
|
|
|
|
from mycroft.api import DeviceApi
|
|
|
|
api = DeviceApi()
|
|
|
|
api.update_version()
|
|
|
|
except BackendDown:
|
|
|
|
data = {'utterance': dialog.get("backend.down")}
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.emit(Message("speak", data))
|
|
|
|
bus.emit(Message("backend.down"))
|
2018-03-27 23:51:30 +00:00
|
|
|
|
2017-04-25 22:18:43 +00:00
|
|
|
else:
|
|
|
|
thread = Timer(1, check_connection)
|
|
|
|
thread.daemon = True
|
|
|
|
thread.start()
|
|
|
|
|
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
def main():
|
2018-08-22 01:50:50 +00:00
|
|
|
global bus
|
2018-04-03 14:50:53 +00:00
|
|
|
reset_sigint_handler()
|
2017-10-13 07:21:58 +00:00
|
|
|
# Create PID file, prevent multiple instancesof this service
|
2017-10-13 09:22:01 +00:00
|
|
|
mycroft.lock.Lock('skills')
|
2018-08-22 01:50:50 +00:00
|
|
|
# Connect this Skill management process to the Mycroft Messagebus
|
|
|
|
bus = WebsocketClient()
|
|
|
|
Configuration.init(bus)
|
2017-04-06 17:45:28 +00:00
|
|
|
|
2018-08-22 01:50:50 +00:00
|
|
|
bus.on('message', create_echo_function('SKILLS'))
|
|
|
|
# Startup will be called after the connection with the Messagebus is done
|
|
|
|
bus.once('open', _starting_up)
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2018-08-22 01:50:50 +00:00
|
|
|
create_daemon(bus.run_forever)
|
2018-04-03 14:50:53 +00:00
|
|
|
wait_for_exit_signal()
|
|
|
|
shutdown()
|
2017-04-06 17:45:28 +00:00
|
|
|
|
2017-04-17 17:25:27 +00:00
|
|
|
|
2018-04-03 14:50:53 +00:00
|
|
|
def shutdown():
|
|
|
|
if event_scheduler:
|
|
|
|
event_scheduler.shutdown()
|
|
|
|
|
|
|
|
# Terminate all running threads that update skills
|
|
|
|
if skill_manager:
|
|
|
|
skill_manager.stop()
|
|
|
|
skill_manager.join()
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2018-04-03 14:50:53 +00:00
|
|
|
main()
|