Esempio n. 1
0
def main():
    global ws
    lock = Lock('skills')  # prevent multiple instances of this service

    # Connect this Skill management process to the websocket
    ws = WebsocketClient()
    ConfigurationManager.init(ws)

    ignore_logs = ConfigurationManager.instance().get("ignore_logs")

    # Listen for messages and echo them for logging
    def _echo(message):
        try:
            _message = json.loads(message)

            if _message.get("type") in ignore_logs:
                return

            if _message.get("type") == "registration":
                # do not log tokens from registration messages
                _message["data"]["token"] = None
            message = json.dumps(_message)
        except:
            pass
        logger.debug(message)

    ws.on('message', _echo)

    # Startup will be called after websocket is full live
    ws.once('open', _starting_up)
    ws.run_forever()
Esempio n. 2
0
def main():
    global ws
    global config
    ws = WebsocketClient()
    Configuration.init(ws)
    config = Configuration.get()
    speech.init(ws)

    # Setup control of pulse audio
    setup_pulseaudio_handlers(config.get('Audio').get('pulseaudio'))

    def echo(message):
        try:
            _message = json.loads(message)
            if 'mycroft.audio.service' not in _message.get('type'):
                return
            message = json.dumps(_message)
        except:
            pass
        LOG.debug(message)

    LOG.info("Staring Audio Services")
    ws.on('message', echo)
    ws.once('open', load_services_callback)
    try:
        ws.run_forever()
    except KeyboardInterrupt, e:
        LOG.exception(e)
        speech.shutdown()
        sys.exit()
Esempio n. 3
0
def simple_cli():
    global bus
    global bSimple
    bSimple = True
    bus = WebsocketClient()  # Mycroft messagebus connection
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    bus.on('speak', handle_speak)
    try:
        while True:
            # Sleep for a while so all the output that results
            # from the previous command finishes before we print.
            time.sleep(1.5)
            print("Input (Ctrl+C to quit):")
            line = sys.stdin.readline()
            bus.emit(Message("recognizer_loop:utterance",
                             {'utterances': [line.strip()]}))
    except KeyboardInterrupt as e:
        # User hit Ctrl+C to quit
        print("")
    except KeyboardInterrupt as e:
        LOG.exception(e)
        event_thread.exit()
        sys.exit()
Esempio n. 4
0
def main():
    global client
    global loop
    client = WebsocketClient()
    device_index = config.get('speech_client').get('device_index')
    if device_index:
        device_index = int(device_index)
    loop = RecognizerLoop(device_index=device_index)
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('recognizer_loop:record_begin', handle_record_begin)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:record_end', handle_record_end)
    loop.on('speak', handle_speak)
    client.on('speak', handle_speak)
    client.on(
        'multi_utterance_intent_failure',
        handle_multi_utterance_intent_failure)
    client.on('recognizer_loop:sleep', handle_sleep)
    client.on('recognizer_loop:wake_up', handle_wake_up)
    client.on('mycroft.stop', handle_stop)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    try:
        subprocess.call('echo "eyes.reset" >/dev/ttyAMA0', shell=True)
    except:
        pass

    try:
        loop.run()
    except KeyboardInterrupt, e:
        logger.exception(e)
        event_thread.exit()
        sys.exit()
Esempio n. 5
0
class WebSocketHandler(tornado.websocket.WebSocketHandler):
    peer = "unknown"

    def create_internal_emitter(self):
        # connect to mycroft internal websocket
        self.emitter = WebsocketClient()
        self.register_internal_messages()
        self.emitter_thread = Thread(target=self.connect_to_internal_emitter)
        self.emitter_thread.setDaemon(True)
        self.emitter_thread.start()

    def register_internal_messages(self):
        # catch all messages
        self.emitter.on('speak', self.handle_speak)

    def connect_to_internal_emitter(self):
        self.emitter.run_forever()

    def open(self):
        LOG.info('Client IP: ' + self.request.remote_ip)
        self.peer = self.request.remote_ip
        clients[self.peer] = self
        self.create_internal_emitter()
        self.write_message("Welcome to Jarbas Web Client")

    def on_message(self, message):
        utterance = message.strip()
        LOG.info("Utterance : " + utterance)
        if utterance:
            if utterance == '"mic_on"':
                create_signal('startListening')
            else:
                data = {"utterances": [utterance], "lang": lang}
                context = {
                    "source": self.peer,
                    "destinatary": "skills",
                    "client_name": platform,
                    "peer": self.peer
                }
                self.emitter.emit(
                    Message("recognizer_loop:utterance", data, context))

    def handle_speak(self, event):
        if event.context.get("client_name", platform) == platform:
            peer = event.context.get("peer", "")
            if peer == self.peer:
                self.write_message(event.data['utterance'])

    def on_close(self):
        global clients
        self.emitter.remove("speak", self.handle_speak)
        clients.pop(self.peer)
Esempio n. 6
0
def main():
    global skill_response, wait_response, port, lang
    wait_response = True
    skill_response = ""

    global ws
    ws = WebsocketClient()
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    ws.on('speak', handle_speak)

    import tornado.options

    tornado.options.parse_command_line()
    config = ConfigurationManager.get().get("websocket")
    lang = ConfigurationManager.get().get("lang")

    port = "9090"
    url = ("http://" + str(ip) + ":" + str(port))
    print("*********************************************************")
    print("*   JCASOFT - Mycroft Web Cliento ")
    print("*")
    print("*   Access from web browser " + url)
    print("*********************************************************")

    routes = [
        tornado.web.url(r"/", MainHandler, name="main"),
        tornado.web.url(r"/static/(.*)", tornado.web.StaticFileHandler,
                        {'path': './'}),
        tornado.web.url(r"/ws", WebSocketHandler)
    ]

    settings = {
        "debug": True,
        "template_path": os.path.join(os.path.dirname(__file__), "templates"),
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
    }

    application = tornado.web.Application(routes, **settings)
    httpServer = tornado.httpserver.HTTPServer(application)
    tornado.options.parse_command_line()
    httpServer.listen(port)

    try:
        tornado.ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        logger.exception(e)
        event_thread.exit()
        tornado.ioloop.IOLoop.instance().stop()
        sys.exit()
def main():
    global skill_response, wait_response, port, lang
    wait_response = True
    skill_response = ""

    global ws
    ws = WebsocketClient()
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    ws.on('speak', handle_speak)

    import tornado.options

    tornado.options.parse_command_line()
    config = ConfigurationManager.get().get("websocket")
    lang = ConfigurationManager.get().get("lang")

    host = config.get("host")
    port = config.get("port")
    route = config.get("route")
    validate_param(host, "websocket.host")
    validate_param(port, "websocket.port")
    validate_param(route, "websocket.route")


    url = "http://" + str(ip)+":"+str(port)
    print "*********************************************************"
    print "*   Access from web browser " + url
    print "*********************************************************"

    routes = [
        (route, WebsocketEventHandler),
	tornado.web.url(r"/", MainHandler, name="main"),
	tornado.web.url(r"/static/(.*)", tornado.web.StaticFileHandler, {'path':  './'}),
	tornado.web.url(r"/ws", WebSocketHandler)
    ]

    settings = {
        "debug": True,
        "template_path": os.path.join(os.path.dirname(__file__), "templates"),
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
    }
    

    application = tornado.web.Application(routes, **settings)
    httpServer = tornado.httpserver.HTTPServer(application)
    tornado.options.parse_command_line()
    httpServer.listen(port)
    tornado.ioloop.IOLoop.instance().start()
Esempio n. 8
0
def main():
    global client
    global loop
    client = WebsocketClient()
    device_index = config.get('speech_client').get('device_index')
    if device_index:
        device_index = int(device_index)
    loop = RecognizerLoop(device_index=device_index)
    loop.on('recognizer_loop:listening', handle_listening)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('speak', handle_speak)
    client.on('speak', handle_speak)
    client.on(
        'multi_utterance_intent_failure',
        handle_multi_utterance_intent_failure)
    client.on('recognizer_loop:sleep', handle_sleep)
    client.on('recognizer_loop:wake_up', handle_wake_up)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    try:
        loop.run()
    except KeyboardInterrupt, e:
        event_thread.exit()
        sys.exit()
Esempio n. 9
0
def main():
    global client
    global loop
    client = WebsocketClient()
    device_index = config.get('speech_client').get('device_index')
    if device_index:
        device_index = int(device_index)
    loop = RecognizerLoop(device_index=device_index)
    loop.on('recognizer_loop:listening', handle_listening)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('speak', handle_speak)
    client.on('speak', handle_speak)
    client.on('multi_utterance_intent_failure',
              handle_multi_utterance_intent_failure)
    client.on('recognizer_loop:sleep', handle_sleep)
    client.on('recognizer_loop:wake_up', handle_wake_up)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    try:
        loop.run()
    except KeyboardInterrupt, e:
        event_thread.exit()
        sys.exit()
Esempio n. 10
0
def main():
    global bus
    reset_sigint_handler()
    # Create PID file, prevent multiple instancesof this service
    mycroft.lock.Lock('skills')
    # Connect this Skill management process to the Mycroft Messagebus
    bus = WebsocketClient()
    Configuration.init(bus)

    bus.on('message', create_echo_function('SKILLS'))
    # Startup will be called after the connection with the Messagebus is done
    bus.once('open', _starting_up)

    create_daemon(bus.run_forever)
    wait_for_exit_signal()
    shutdown()
Esempio n. 11
0
def main():
    global bus
    reset_sigint_handler()
    # Create PID file, prevent multiple instancesof this service
    mycroft.lock.Lock('skills')
    # Connect this Skill management process to the Mycroft Messagebus
    bus = WebsocketClient()
    Configuration.init(bus)

    bus.on('message', create_echo_function('SKILLS'))
    # Startup will be called after the connection with the Messagebus is done
    bus.once('open', _starting_up)

    create_daemon(bus.run_forever)
    wait_for_exit_signal()
    shutdown()
Esempio n. 12
0
File: main.py Progetto: hungnt1/core
def main():
    """ Main function. Run when file is invoked. """
    reset_sigint_handler()
    ws = WebsocketClient()
    Configuration.init(ws)
    speech.init(ws)

    LOG.info("Starting Audio Services")
    ws.on('message', create_echo_function('AUDIO', ['mycroft.audio.service']))
    audio = AudioService(ws)  # Connect audio service instance to message bus
    create_daemon(ws.run_forever)

    wait_for_exit_signal()

    speech.shutdown()
    audio.shutdown()
Esempio n. 13
0
def main():
    global client
    client = WebsocketClient()
    if not '--quiet' in sys.argv:
        client.on('speak', handle_speak)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    try:
        while True:
            print("Input:")
            line = sys.stdin.readline()
            client.emit(Message("recognizer_loop:utterance", metadata={'utterances': [line.strip()]}))
    except KeyboardInterrupt, e:
        event_thread.exit()
        sys.exit()
Esempio n. 14
0
class Enclosure:
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """

    def __init__(self):
        self.__init_serial()
        self.client = WebsocketClient()
        self.reader = EnclosureReader(self.serial, self.client)
        self.writer = EnclosureWriter(self.serial, self.client)
        self.eyes = EnclosureEyes(self.client, self.writer)
        self.mouth = EnclosureMouth(self.client, self.writer)
        self.system = EnclosureArduino(self.client, self.writer)
        self.__init_events()

    def __init_serial(self):
        try:
            self.config = ConfigurationManager.get_config().get("enclosure")
            self.port = self.config.get("port")
            self.rate = int(self.config.get("rate"))
            self.timeout = int(self.config.get("timeout"))
            self.serial = serial.serial_for_url(
                url=self.port, baudrate=self.rate, timeout=self.timeout)
            LOGGER.info(
                "Connected to: " + self.port + " rate: " + str(self.rate) +
                " timeout: " + str(self.timeout))
        except:
            LOGGER.error(
                "It is not possible to connect to serial port: " + self.port)
            raise

    def __init_events(self):
        self.client.on('recognizer_loop:listening', self.mouth.listen)
        self.client.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.client.on('recognizer_loop:audio_output_end', self.mouth.reset)
        self.client.on('recognizer_loop:wakeword', self.eyes.blink)

    def run(self):
        try:
            self.client.run_forever()
        except Exception as e:
            LOGGER.error("Client error: {0}".format(e))
            self.stop()

    def stop(self):
        self.writer.stop()
        self.reader.stop()
        self.serial.close()
Esempio n. 15
0
def main():
    """ Main function. Run when file is invoked. """
    reset_sigint_handler()
    check_for_signal("isSpeaking")
    bus = WebsocketClient()  # Connect to the Mycroft Messagebus
    Configuration.init(bus)
    speech.init(bus)

    LOG.info("Starting Audio Services")
    bus.on('message', create_echo_function('AUDIO', ['mycroft.audio.service']))
    audio = AudioService(bus)  # Connect audio service instance to message bus
    create_daemon(bus.run_forever)

    wait_for_exit_signal()

    speech.shutdown()
    audio.shutdown()
Esempio n. 16
0
class Enclosure:
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """
    def __init__(self):
        self.__init_serial()
        self.client = WebsocketClient()
        self.reader = EnclosureReader(self.serial, self.client)
        self.writer = EnclosureWriter(self.serial, self.client)
        self.eyes = EnclosureEyes(self.client, self.writer)
        self.mouth = EnclosureMouth(self.client, self.writer)
        self.system = EnclosureArduino(self.client, self.writer)
        self.__init_events()

    def __init_serial(self):
        try:
            self.config = ConfigurationManager.get_config().get("enclosure")
            self.port = self.config.get("port")
            self.rate = int(self.config.get("rate"))
            self.timeout = int(self.config.get("timeout"))
            self.serial = serial.serial_for_url(url=self.port,
                                                baudrate=self.rate,
                                                timeout=self.timeout)
            LOGGER.info("Connected to: " + self.port + " rate: " +
                        str(self.rate) + " timeout: " + str(self.timeout))
        except:
            LOGGER.error("It is not possible to connect to serial port: " +
                         self.port)
            raise

    def __init_events(self):
        self.client.on('recognizer_loop:listening', self.mouth.listen)
        self.client.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.client.on('recognizer_loop:audio_output_end', self.mouth.reset)
        self.client.on('recognizer_loop:wakeword', self.eyes.blink)

    def run(self):
        try:
            self.client.run_forever()
        except Exception as e:
            LOGGER.error("Client error: {0}".format(e))
            self.stop()

    def stop(self):
        self.writer.stop()
        self.reader.stop()
        self.serial.close()
Esempio n. 17
0
def main():
    global ws
    ws = WebsocketClient()
    if '--quiet' not in sys.argv:
        ws.on('speak', handle_speak)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    try:
        while True:
            print("Input:")
            line = sys.stdin.readline()
            ws.emit(
                Message("recognizer_loop:utterance",
                        {'utterances': [line.strip()]}))
    except KeyboardInterrupt, e:
        logger.exception(e)
        event_thread.exit()
        sys.exit()
Esempio n. 18
0
def main():
    global client
    client = WebsocketClient()

    def echo(message):
        try:
            _message = json.loads(message)

            if _message.get("message_type") == "registration":
                # do not log tokens from registration messages
                _message["metadata"]["token"] = None
            message = json.dumps(_message)
        except:
            pass
        logger.debug(message)

    client.on('message', echo)
    client.once('open', load_skills_callback)
    client.run_forever()
Esempio n. 19
0
def main():
    global ws
    ws = WebsocketClient()
    ConfigurationManager.init(ws)

    def echo(message):
        try:
            _message = json.loads(message)

            if _message.get("type") == "registration":
                # do not log tokens from registration messages
                _message["data"]["token"] = None
            message = json.dumps(_message)
        except:
            pass
        logger.debug(message)

    ws.on('message', echo)
    ws.once('open', load_skills_callback)
    ws.run_forever()
Esempio n. 20
0
def main():
    global ws
    ws = WebsocketClient()
    ConfigurationManager.init(ws)

    def echo(message):
        try:
            _message = json.loads(message)

            if _message.get("type") == "registration":
                # do not log tokens from registration messages
                _message["data"]["token"] = None
            message = json.dumps(_message)
        except:
            pass
        logger.debug(message)

    ws.on('message', echo)
    ws.once('open', load_skills_callback)
    ws.run_forever()
Esempio n. 21
0
class SkillContainer(object):
    def __init__(self, args):
        parser = argparse.ArgumentParser()
        parser.add_argument("--dependency-dir", default="./lib")
        parser.add_argument("--messagebus-host", default=messagebus_config.get("host"))
        parser.add_argument("--messagebus-port", type=int, default=messagebus_config.get("port"))
        parser.add_argument("--use-ssl", action='store_true', default=False)
        parser.add_argument("--enable-intent-skill", action='store_true', default=False)
        parser.add_argument("skill_directory", default=os.path.dirname(__file__))

        parsed_args = parser.parse_args(args)
        if os.path.exists(parsed_args.dependency_dir):
            sys.path.append(parsed_args.dependency_dir)

        self.skill_directory = parsed_args.skill_directory
        self.enable_intent_skill = parsed_args.enable_intent_skill

        self.client = WebsocketClient(host=parsed_args.messagebus_host,
                                      port=parsed_args.messagebus_port,
                                      ssl=parsed_args.use_ssl)

    def try_load_skill(self):
        if self.enable_intent_skill:
            intent_skill = create_intent_skill()
            intent_skill.bind(self.client)
            intent_skill.initialize()
        skill_descriptor = create_skill_descriptor(self.skill_directory)
        load_skill(skill_descriptor, self.client)

    def run(self):
        self.client.on('message', logger.debug)
        self.client.on('open', self.try_load_skill)
        self.client.on('error', logger.error)
        self.client.run_forever()
Esempio n. 22
0
def listener():
    rospy.init_node('mycroft_skills')
    rospy.loginfo(rospy.get_caller_id() + " started")
    rospy.Subscriber("mycroft/utterance", String, handle_utterance)
    rospy.Subscriber("mycroft/remove_skill", String, handle_remove_skill)
    s = rospy.Service('mycroft/register_skill', MycroftService,
                      handle_register_skill)

    global bus
    reset_sigint_handler()
    # Create PID file, prevent multiple instancesof this service
    mycroft.lock.Lock('skills')
    # Connect this Skill management process to the Mycroft Messagebus
    bus = WebsocketClient()
    Configuration.init(bus)
    config = Configuration.get()
    # Set the active lang to match the configured one
    set_active_lang(config.get('lang', 'en-us'))

    bus.on('skill.manager.initialised', initialise_response_server)
    bus.on('message', create_echo_function('SKILLS'))
    # Startup will be called after the connection with the Messagebus is done
    bus.once('open', _starting_up)
    bus.on('skill.converse.request', check_working)

    create_daemon(bus.run_forever)
    wait_for_exit_signal()
    shutdown()

    rospy.spin()
def catchInput(queryInput):
	bus = dbus.SessionBus()
	remote_object = bus.get_object("com.mycroftkde.KDEPlasmoid","/ComMycroftkdeKDEPlasmoidInterface")  
	global client
    	client = WebsocketClient()
    	if '--quiet' not in sys.argv:
        	client.on('speak', handle_speak)
    	event_thread = Thread(target=connect)
    	event_thread.setDaemon(True)
    	event_thread.start()
    	try:
    	    while True:
    	        print("DebuggingGui")
    	        line = remote_object.sendQuery(guioutputstring,dbus_interface = "com.mycroftkde.KDEPlasmoid")
    	        client.emit(
    	            Message("recognizer_loop:utterance",
    	                    metadata={'utterances': [line.strip()]}))
		line = ("")
		return 
    	except KeyboardInterrupt, e:
    	    logger.exception(e)
    	    event_thread.exit()
	    sys.exit()	
Esempio n. 24
0
class SkillContainer(object):
    def __init__(self, args):
        params = self.__build_params(args)

        if params.config:
            ConfigurationManager.load_local([params.config])

        if exists(params.lib) and isdir(params.lib):
            sys.path.append(params.lib)

        sys.path.append(params.dir)
        self.dir = params.dir

        self.enable_intent_skill = params.enable_intent_skill

        self.__init_client(params)

    @staticmethod
    def __build_params(args):
        parser = argparse.ArgumentParser()
        parser.add_argument("--config", default="./mycroft.ini")
        parser.add_argument("--dir", default=dirname(__file__))
        parser.add_argument("--lib", default="./lib")
        parser.add_argument("--host", default=None)
        parser.add_argument("--port", default=None)
        parser.add_argument("--use-ssl", action='store_true', default=False)
        parser.add_argument("--enable-intent-skill",
                            action='store_true',
                            default=False)
        return parser.parse_args(args)

    def __init_client(self, params):
        config = ConfigurationManager.get().get("messagebus_client")

        if not params.host:
            params.host = config.get('host')
        if not params.port:
            params.port = config.get('port')

        self.client = WebsocketClient(host=params.host,
                                      port=params.port,
                                      ssl=params.use_ssl)

    def try_load_skill(self):
        if self.enable_intent_skill:
            intent_skill = create_intent_skill()
            intent_skill.bind(self.client)
            intent_skill.initialize()
        skill_descriptor = create_skill_descriptor(self.dir)
        load_skill(skill_descriptor, self.client)

    def run(self):
        self.client.on('message', logger.debug)
        self.client.on('open', self.try_load_skill)
        self.client.on('error', logger.error)
        self.client.run_forever()
def catchInput(queryInput):
	bus = dbus.SessionBus()
	remote_object = bus.get_object("org.gnome.Shell","/com/mycroftaignome/MycroftGnomeResult")  
	getText = remote_object.sendQuery(guioutputstring,dbus_interface = "com.mycroftaignome.MycroftAiGnomeBox")	
	print getText	
 	global client
	client = WebsocketClient()
	client.on('speak', handle_speak)
	event_thread = Thread(target=connect)
	event_thread.setDaemon(True)
	event_thread.start()
	try:
		while True:
		
       			print("Input:")
      	 		queryInput= object.sendQuery(guioutputstring,dbus_interface = "com.mycroftaignome.MycroftAiGnomeBox")
      			client.emit(
      		          Message("recognizer_loop:utterance",
      		                  metadata={'utterances': [queryInput]}))
			break
    	except KeyboardInterrupt, e:
        	logger.exception(e)
        	event_thread.exit()
		sys.exit()		
Esempio n. 26
0
def main():
    rospy.init_node('mycroft_tts')
    rospy.loginfo(rospy.get_caller_id() + " started")
    rospy.Subscriber("mycroft/speak", String, handle_speak)
    rospy.Subscriber("mycroft/stop", String, handle_stop)
    """ Main function. Run when file is invoked. """
    global bus
    reset_sigint_handler()
    check_for_signal("isSpeaking")
    bus = WebsocketClient()  # Connect to the Mycroft Messagebus
    Configuration.init(bus)
    speech.init(bus)

    LOG.info("Starting Audio Services")
    bus.on('message', create_echo_function('AUDIO', ['mycroft.audio.service']))
    audio = AudioService(bus)  # Connect audio service instance to message bus
    create_daemon(bus.run_forever)

    wait_for_exit_signal()

    speech.shutdown()
    audio.shutdown()
    # keep node running
    rospy.spin()
Esempio n. 27
0
def simple_cli():
    global ws
    ws = WebsocketClient()
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    ws.on('speak', handle_speak)
    try:
        while True:
            # Sleep for a while so all the output that results
            # from the previous command finishes before we print.
            time.sleep(1.5)
            print("Input (Ctrl+C to quit):")
            line = sys.stdin.readline()
            ws.emit(
                Message("recognizer_loop:utterance",
                        {'utterances': [line.strip()]}))
    except KeyboardInterrupt as e:
        # User hit Ctrl+C to quit
        print("")
    except KeyboardInterrupt as e:
        LOG.exception(e)
        event_thread.exit()
        sys.exit()
Esempio n. 28
0
class SkillContainer(object):
    def __init__(self, args):
        params = self.__build_params(args)

        if params.config:
            ConfigurationManager.load_local([params.config])

        if exists(params.lib) and isdir(params.lib):
            sys.path.append(params.lib)

        sys.path.append(params.dir)
        self.dir = params.dir

        self.enable_intent_skill = params.enable_intent_skill

        self.__init_client(params)

    @staticmethod
    def __build_params(args):
        parser = argparse.ArgumentParser()
        parser.add_argument("--config", default="./mycroft.ini")
        parser.add_argument("dir", nargs='?', default=dirname(__file__))
        parser.add_argument("--lib", default="./lib")
        parser.add_argument("--host", default=None)
        parser.add_argument("--port", default=None)
        parser.add_argument("--use-ssl", action='store_true', default=False)
        parser.add_argument("--enable-intent-skill", action='store_true',
                            default=False)
        return parser.parse_args(args)

    def __init_client(self, params):
        config = ConfigurationManager.get().get("messagebus_client")

        if not params.host:
            params.host = config.get('host')
        if not params.port:
            params.port = config.get('port')

        self.client = WebsocketClient(host=params.host,
                                      port=params.port,
                                      ssl=params.use_ssl)

    def try_load_skill(self):
        if self.enable_intent_skill:
            intent_skill = create_intent_skill()
            intent_skill.bind(self.client)
            intent_skill.initialize()
        skill_descriptor = create_skill_descriptor(self.dir)
        load_skill(skill_descriptor, self.client)

    def run(self):
        self.client.on('message', logger.debug)
        self.client.on('open', self.try_load_skill)
        self.client.on('error', logger.error)
        self.client.run_forever()
Esempio n. 29
0
def launch(config=None):
    global app, ws, intents, timeout
    config = config or Configuration.get().get("hivemind", {}).get("flask_node", {})
    # connect to internal mycroft
    ws = WebsocketClient()
    ws.on("mycroft.skill.handler.complete", end_wait)
    ws.on("complete_intent_failure", end_wait)
    ws.on("speak", listener)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
    port = config.get("port", 6712)
    timeout = config.get("timeout", timeout)
    intents = MicroIntentService(ws)
    start(app, port)
Esempio n. 30
0
class DevicePairingClient(object):
    def __init__(self, config=_config, pairing_code=None):
        self.config = config
        self.paired = False
        self.ws_client = WebsocketClient(host=config.get("host"),
                                         port=config.get("port"),
                                         path=config.get("route"),
                                         ssl=str2bool(config.get("ssl")))
        self.identity_manager = IdentityManager()
        self.identity = self.identity_manager.identity
        self.pairing_code = (
            pairing_code if pairing_code else generate_pairing_code())

    def on_registration(self, message):
        # TODO: actually accept the configuration message and store it in
        # identity
        identity = self.identity_manager.get()
        register_payload = message.metadata
        if register_payload.get("device_id") == identity.device_id:
            identity.token = register_payload.get('token')
            identity.owner = register_payload.get('user')
            self.identity_manager.update(identity)
            self.ws_client.close()
            self.paired = True

    def send_device_info(self):
        msg = Message("device_info",
                      metadata={
                          "pairing_code": self.pairing_code,
                          "device_id": self.identity.device_id
                      })

        self.ws_client.emit(msg)

    @staticmethod
    def print_error(message):
        print(repr(message))

    def run(self):
        self.ws_client.on('registration', self.on_registration)
        self.ws_client.on('open', self.send_device_info)
        self.ws_client.on('error', self.print_error)
        self.ws_client.run_forever()
Esempio n. 31
0
class DevicePairingClient(object):
    def __init__(self, config=_config, pairing_code=None):
        self.config = config
        self.paired = False
        self.ws_client = WebsocketClient(host=config.get("host"),
                                         port=config.get("port"),
                                         path=config.get("route"),
                                         ssl=str2bool(config.get("ssl")))
        self.identity_manager = IdentityManager()
        self.identity = self.identity_manager.identity
        self.pairing_code = (pairing_code
                             if pairing_code else generate_pairing_code())

    def on_registration(self, message):
        # TODO: actually accept the configuration message and store it in
        # identity
        identity = self.identity_manager.get()
        register_payload = message.metadata
        if register_payload.get("device_id") == identity.device_id:
            identity.token = register_payload.get('token')
            identity.owner = register_payload.get('user')
            self.identity_manager.update(identity)
            self.ws_client.close()
            self.paired = True

    def send_device_info(self):
        msg = Message("device_info",
                      metadata={
                          "pairing_code": self.pairing_code,
                          "device_id": self.identity.device_id
                      })

        self.ws_client.emit(msg)

    @staticmethod
    def print_error(message):
        print(repr(message))

    def run(self):
        self.ws_client.on('registration', self.on_registration)
        self.ws_client.on('open', self.send_device_info)
        self.ws_client.on('error', self.print_error)
        self.ws_client.run_forever()
Esempio n. 32
0
class SkillContainer(object):
    def __init__(self, args):
        parser = argparse.ArgumentParser()
        parser.add_argument("--dependency-dir", default="./lib")
        parser.add_argument("--messagebus-host",
                            default=messagebus_config.get("host"))
        parser.add_argument("--messagebus-port",
                            type=int,
                            default=messagebus_config.get("port"))
        parser.add_argument("--use-ssl", action='store_true', default=False)
        parser.add_argument("--enable-intent-skill",
                            action='store_true',
                            default=False)
        parser.add_argument("skill_directory",
                            default=os.path.dirname(__file__))

        parsed_args = parser.parse_args(args)
        if os.path.exists(parsed_args.dependency_dir):
            sys.path.append(parsed_args.dependency_dir)
        sys.path.append(parsed_args.skill_directory)

        self.skill_directory = parsed_args.skill_directory

        self.enable_intent_skill = parsed_args.enable_intent_skill

        self.client = WebsocketClient(host=parsed_args.messagebus_host,
                                      port=parsed_args.messagebus_port,
                                      ssl=parsed_args.use_ssl)

    def try_load_skill(self):
        if self.enable_intent_skill:
            intent_skill = create_intent_skill()
            intent_skill.bind(self.client)
            intent_skill.initialize()
        skill_descriptor = create_skill_descriptor(self.skill_directory)
        load_skill(skill_descriptor, self.client)

    def run(self):
        self.client.on('message', logger.debug)
        self.client.on('open', self.try_load_skill)
        self.client.on('error', logger.error)
        self.client.run_forever()
Esempio n. 33
0
def init_display_manager_bus_connection():
    """ Connects the display manager to the messagebus """
    LOG.info("Connecting display manager to messagebus")

    # Should remove needs to be an object so it can be referenced in functions
    # [https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference]
    display_manager = DisplayManager()
    should_remove = [True]

    def check_flag(flag):
        if flag[0] is True:
            display_manager.remove_active()

    def set_delay(event=None):
        should_remove[0] = True
        Timer(2, check_flag, [should_remove]).start()

    def set_remove_flag(event=None):
        should_remove[0] = False

    def connect():
        bus.run_forever()

    def remove_wake_word():
        data = _read_data()
        if "active_skill" in data and data["active_skill"] == "wakeword":
            display_manager.remove_active()

    def set_wakeword_skill(event=None):
        display_manager.set_active("wakeword")
        Timer(10, remove_wake_word).start()

    bus = WebsocketClient()
    bus.on('recognizer_loop:audio_output_end', set_delay)
    bus.on('recognizer_loop:audio_output_start', set_remove_flag)
    bus.on('recognizer_loop:record_begin', set_wakeword_skill)

    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
Esempio n. 34
0
def init_display_manager_bus_connection():
    """ Connects the display manager to the messagebus """
    LOG.info("Connecting display manager to messagebus")

    # Should remove needs to be an object so it can be referenced in functions
    # [https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference]
    display_manager = DisplayManager()
    should_remove = [True]

    def check_flag(flag):
        if flag[0] is True:
            display_manager.remove_active()

    def set_delay(event=None):
        should_remove[0] = True
        Timer(2, check_flag, [should_remove]).start()

    def set_remove_flag(event=None):
        should_remove[0] = False

    def connect():
        bus.run_forever()

    def remove_wake_word():
        data = _read_data()
        if "active_skill" in data and data["active_skill"] == "wakeword":
            display_manager.remove_active()

    def set_wakeword_skill(event=None):
        display_manager.set_active("wakeword")
        Timer(10, remove_wake_word).start()

    bus = WebsocketClient()
    bus.on('recognizer_loop:audio_output_end', set_delay)
    bus.on('recognizer_loop:audio_output_start', set_remove_flag)
    bus.on('recognizer_loop:record_begin', set_wakeword_skill)

    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()
Esempio n. 35
0
from mycroft.messagebus.message import Message

if len(sys.argv) == 2:
    messageToSend = sys.argv[1]
elif len(sys.argv) > 2:
    messageToSend = " ".join(sys.argv[2:])
else:
    filename = os.path.basename(__file__)
    print filename
    print "Simple command line interface to the messagebus."
    print "Usage:   messagebus_emit <utterance>\n"
    print "         where <utterance> is treated as if spoken to Mycroft."
    print "Example: " + filename + " mycroft.wifi.start"
    exit()


def onConnected(event=None):
    print "Sending message...'" + messageToSend + "'"
    messagebusClient.emit(Message(messageToSend))
    messagebusClient.close()
    exit()


# Establish a connection with the messagebus
messagebusClient = WebsocketClient()
messagebusClient.on('connected', onConnected)


# This will block until the client gets closed
messagebusClient.run_forever()
Esempio n. 36
0
class WiFi:
    def __init__(self):
        self.iface = pyw.winterfaces()[0]
        self.ap = AccessPoint(self.iface)
        self.server = None
        self.ws = WebsocketClient()
        self.enclosure = EnclosureAPI(self.ws)
        self.init_events()
        self.conn_monitor = None
        self.conn_monitor_stop = threading.Event()
        self.starting = False

    def init_events(self):
        '''
            Register handlers for various websocket events used
            to communicate with outside systems.
        '''

        # This event is generated by an outside mechanism.  On a
        # Mark 1 unit this comes from the Enclosure's WIFI menu
        # item being selected.
        self.ws.on('mycroft.wifi.start', self.start)

        # Similar to the above.  Resets to factory defaults
        self.ws.on('mycroft.wifi.reset', self.reset)

        # Similar to the above.  Enable/disable SSH
        self.ws.on('mycroft.enable.ssh', self.ssh_enable)
        self.ws.on('mycroft.disable.ssh', self.ssh_disable)

        # These events are generated by Javascript in the captive
        # portal.
        self.ws.on('mycroft.wifi.stop', self.stop)
        self.ws.on('mycroft.wifi.scan', self.scan)
        self.ws.on('mycroft.wifi.connect', self.connect)

    def start(self, event=None):
        '''
           Fire up the MYCROFT access point for the user to connect to
           with a phone or computer.
        '''
        if self.starting:
            return

        self.starting = True
        LOG.info("Starting access point...")

        self.intro_msg = ""
        if event and event.data.get("msg"):
            self.intro_msg = event.data.get("msg")
        self.allow_timeout = True
        if event and event.data.get("allow_timeout"):
            self.allow_timeout = event.data.get("allow_timeout")

        # Fire up our access point
        self.ap.up()
        if not self.server:
            LOG.info("Creating web server...")
            self.server = WebServer(self.ap.ip, 80)
            LOG.info("Starting web server...")
            self.server.start()
            LOG.info("Created web server.")

        LOG.info("Access point started!\n%s" % self.ap.__dict__)
        self._start_connection_monitor()

    def _connection_prompt(self, intro):
        while self.ap.password is None or self.ap.password == "":
            sleep(1)  # give it time to load

        # Speak the connection instructions and show the password on screen
        passwordSpelled = ",  ".join(self.ap.password)
        self._speak_and_show(intro +
                             " Use your mobile device or computer to connect "
                             "to the wifi network 'MYCROFT'.  Then enter the "
                             "password " + passwordSpelled,
                             self.ap.password)

    def _speak_and_show(self, speak, show):
        ''' Communicate with the user throughout the process '''
        self.ws.emit(Message("speak", {'utterance': speak}))
        if show is None:
            return

        wait_while_speaking()
        self.enclosure.mouth_text(show)

    def _start_connection_monitor(self):
        LOG.info("Starting monitor thread...\n")
        if self.conn_monitor is not None:
            LOG.info("Killing old thread...\n")
            self.conn_monitor_stop.set()
            self.conn_monitor_stop.wait()

        self.conn_monitor = threading.Thread(
            target=self._do_connection_monitor,
            args={})
        self.conn_monitor.daemon = True
        self.conn_monitor.start()
        LOG.info("Monitor thread setup complete.\n")

    def _stop_connection_monitor(self):
        ''' Set flag that will let monitoring thread close '''
        self.conn_monitor_stop.set()

    def _do_connection_monitor(self):
        LOG.info("Invoked monitor thread...\n")
        mtimeLast = os.path.getmtime('/var/lib/misc/dnsmasq.leases')
        bHasConnected = False
        cARPFailures = 0
        timeStarted = time.time()
        timeLastAnnounced = timeStarted - 45  # first reminder in 90 secs
        self.conn_monitor_stop.clear()

        while not self.conn_monitor_stop.isSet():
            # do our monitoring...
            mtime = os.path.getmtime('/var/lib/misc/dnsmasq.leases')
            if mtimeLast != mtime:
                # Something changed in the dnsmasq lease file -
                # presumably a (re)new lease
                bHasConnected = True
                cARPFailures = 0
                mtimeLast = mtime
                timeStarted = time.time()  # reset start time after connection
                timeLastAnnounced = time.time() - 45  # announce how to connect

            if time.time() - timeStarted > 60 * 5 and self.allow_timeout:
                # After 5 minutes, shut down the access point (unless the
                # system has never been setup, in which case we stay up
                # indefinitely)
                LOG.info("Auto-shutdown of access point after 5 minutes")
                self.stop()
                continue

            if time.time() - timeLastAnnounced >= 45:
                if bHasConnected:
                    self._speak_and_show(
                        "Follow the prompt on your mobile device or computer "
                        "and choose a wifi network.  If you don't get a "
                        "prompt, open your browser and go to start dot "
                        "mycroft dot A I.", "start.mycroft.ai")
                else:
                    if self.intro_msg:
                        self._connection_prompt(self.intro_msg)
                        self.intro_msg = None  # only speak the intro once
                    else:
                        self._connection_prompt("Allow me to walk you through "
                                                "the wifi setup process.")

                timeLastAnnounced = time.time()

            if bHasConnected:
                # Flush the ARP entries associated with our access point
                # This will require all network hardware to re-register
                # with the ARP tables if still present.
                if cARPFailures == 0:
                    res = cli_no_output('ip', '-s', '-s', 'neigh', 'flush',
                                        self.ap.subnet + '.0/24')
                    # Give ARP system time to re-register hardware
                    sleep(5)

                # now look at the hardware that has responded, if no entry
                # shows up on our access point after 2*5=10 seconds, the user
                # has disconnected
                if not self._is_ARP_filled():
                    cARPFailures += 1
                    if cARPFailures > 2:
                        self._connection_prompt("Connection lost.")
                        bHasConnected = False
                else:
                    cARPFailures = 0
            sleep(5)  # wait a bit to prevent thread from hogging CPU

        LOG.info("Exiting monitor thread...\n")
        self.conn_monitor_stop.clear()

    def _is_ARP_filled(self):
        res = cli_no_output('/usr/sbin/arp', '-n')
        out = str(res.get("stdout"))
        if out:
            # Parse output, skipping header
            for o in out.split("\n")[1:]:
                if o[0:len(self.ap.subnet)] == self.ap.subnet:
                    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',
                                      ip_disconnected)
                    else:
                        return True  # something on subnet is connected!
        return False

    def scan(self, event=None):
        LOG.info("Scanning wifi connections...")
        networks = {}
        status = self.get_status()

        for cell in Cell.all(self.iface):
            if "x00" in cell.ssid:
                continue  # ignore hidden networks
            update = True
            ssid = cell.ssid
            quality = self.get_quality(cell.quality)

            # If there are duplicate network IDs (e.g. repeaters) only
            # report the strongest signal
            if networks.__contains__(ssid):
                update = networks.get(ssid).get("quality") < quality
            if update and ssid:
                networks[ssid] = {
                    'quality': quality,
                    'encrypted': cell.encrypted,
                    'connected': self.is_connected(ssid, status)
                }
        self.ws.emit(Message("mycroft.wifi.scanned",
                             {'networks': networks}))
        LOG.info("Wifi connections scanned!\n%s" % networks)

    @staticmethod
    def get_quality(quality):
        values = quality.split("/")
        return float(values[0]) / float(values[1])

    def connect(self, event=None):
        if event and event.data:
            ssid = event.data.get("ssid")
            connected = self.is_connected(ssid)

            if connected:
                LOG.warn("Mycroft is already connected to %s" % ssid)
            else:
                self.disconnect()
                LOG.info("Connecting to: %s" % ssid)
                nid = wpa(self.iface, 'add_network')
                wpa(self.iface, 'set_network', nid, 'ssid', '"' + ssid + '"')

                if event.data.__contains__("pass"):
                    psk = '"' + event.data.get("pass") + '"'
                    wpa(self.iface, 'set_network', nid, 'psk', psk)
                else:
                    wpa(self.iface, 'set_network', nid, 'key_mgmt', 'NONE')

                wpa(self.iface, 'enable', nid)
                connected = self.get_connected(ssid)
                if connected:
                    wpa(self.iface, 'save_config')

            self.ws.emit(Message("mycroft.wifi.connected",
                                 {'connected': connected}))
            LOG.info("Connection status for %s = %s" % (ssid, connected))

    def disconnect(self):
        status = self.get_status()
        nid = status.get("id")
        if nid:
            ssid = status.get("ssid")
            wpa(self.iface, 'disable', nid)
            LOG.info("Disconnecting %s id: %s" % (ssid, nid))

    def get_status(self):
        res = cli('wpa_cli', '-i', self.iface, 'status')
        out = str(res.get("stdout"))
        if out:
            return dict(o.split("=") for o in out.split("\n")[:-1])
        return {}

    def get_connected(self, ssid, retry=5):
        connected = self.is_connected(ssid)
        while not connected and retry > 0:
            sleep(2)
            retry -= 1
            connected = self.is_connected(ssid)
        return connected

    def is_connected(self, ssid, status=None):
        status = status or self.get_status()
        state = status.get("wpa_state")
        return status.get("ssid") == ssid and state == "COMPLETED"

    def stop(self, event=None):
        LOG.info("Stopping access point...")
        if is_speaking():
            stop_speaking()  # stop any assistance being spoken
        self._stop_connection_monitor()
        self.ap.down()
        self.enclosure.mouth_reset()  # remove "start.mycroft.ai"
        self.starting = False
        if self.server:
            self.server.server.shutdown()
            self.server.server.server_close()
            self.server.join()
            self.server = None
        LOG.info("Access point stopped!")

    def run(self):
        try:
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def reset(self, event=None):
        """Reset the unit to the factory defaults """
        LOG.info("Resetting the WPA_SUPPLICANT File")
        try:
            call(
                "echo '" + WPA_SUPPLICANT +
                "'> /etc/wpa_supplicant/wpa_supplicant.conf",
                shell=True)
            # UGLY BUT WORKS
            call(RM_SKILLS)
        except Exception as e:
            LOG.error("Error: {0}".format(e))

    def ssh_enable(self, event=None):
        LOG.info("Enabling SSH")
        try:
            call('systemctl enable ssh.service', shell=True)
            call('systemctl start ssh.service', shell=True)
        except Exception as e:
            LOG.error("Error: {0}".format(e))

    def ssh_disable(self, event=None):
        LOG.info("Disabling SSH")
        try:
            call('systemctl stop ssh.service', shell=True)
            call('systemctl disable ssh.service', shell=True)
        except Exception as e:
            LOG.error("Error: {0}".format(e))
Esempio n. 37
0
class SkillContainer(object):
    def __init__(self, args):
        params = self.__build_params(args)

        if params.config:
            Configuration.get([params.config])

        if exists(params.lib) and isdir(params.lib):
            sys.path.append(params.lib)

        sys.path.append(params.dir)
        self.dir = params.dir

        self.enable_intent = params.enable_intent

        self.__init_client(params)

    @staticmethod
    def __build_params(args):
        parser = argparse.ArgumentParser()
        parser.add_argument("--config", default="./mycroft.conf")
        parser.add_argument("dir", nargs='?', default=dirname(__file__))
        parser.add_argument("--lib", default="./lib")
        parser.add_argument("--host", default=None)
        parser.add_argument("--port", default=None)
        parser.add_argument("--use-ssl", action='store_true', default=False)
        parser.add_argument("--enable-intent", action='store_true',
                            default=False)
        return parser.parse_args(args)

    def __init_client(self, params):
        config = Configuration.get().get("websocket")

        if not params.host:
            params.host = config.get('host')
        if not params.port:
            params.port = config.get('port')

        self.ws = WebsocketClient(host=params.host,
                                  port=params.port,
                                  ssl=params.use_ssl)

        # Connect configuration manager to message bus to receive updates
        Configuration.init(self.ws)

    def load_skill(self):
        if self.enable_intent:
            IntentService(self.ws)

        skill_descriptor = create_skill_descriptor(self.dir)
        self.skill = load_skill(skill_descriptor, self.ws, hash(self.dir))

    def run(self):
        try:
            self.ws.on('message', LOG.debug)
            self.ws.on('open', self.load_skill)
            self.ws.on('error', LOG.error)
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def stop(self):
        if self.skill:
            self.skill.shutdown()
Esempio n. 38
0
def main():
    global ws
    global loop
    ws = WebsocketClient()
    tts.init(ws)
    ConfigurationManager.init(ws)
    loop = RecognizerLoop()
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('recognizer_loop:record_begin', handle_record_begin)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:record_end', handle_record_end)
    loop.on('speak', handle_speak)
    ws.on('open', handle_open)
    ws.on('speak', handle_speak)
    ws.on(
        'multi_utterance_intent_failure',
        handle_multi_utterance_intent_failure)
    ws.on('recognizer_loop:sleep', handle_sleep)
    ws.on('recognizer_loop:wake_up', handle_wake_up)
    ws.on('mycroft.stop', handle_stop)
    ws.on("mycroft.paired", handle_paired)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    try:
        loop.run()
    except KeyboardInterrupt, e:
        logger.exception(e)
        event_thread.exit()
        sys.exit()
Esempio n. 39
0
def main():
    global bus
    global loop
    global config
    reset_sigint_handler()
    PIDLock("voice")
    bus = WebsocketClient()  # Mycroft messagebus, see mycroft.messagebus
    Configuration.init(bus)
    config = Configuration.get()

    # Register handlers on internal RecognizerLoop bus
    loop = RecognizerLoop()
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('recognizer_loop:speech.recognition.unknown', handle_unknown)
    loop.on('speak', handle_speak)
    loop.on('recognizer_loop:record_begin', handle_record_begin)
    loop.on('recognizer_loop:awoken', handle_awoken)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:record_end', handle_record_end)
    loop.on('recognizer_loop:no_internet', handle_no_internet)

    # Register handlers for events on main Mycroft messagebus
    bus.on('open', handle_open)
    bus.on('complete_intent_failure', handle_complete_intent_failure)
    bus.on('recognizer_loop:sleep', handle_sleep)
    bus.on('recognizer_loop:wake_up', handle_wake_up)
    bus.on('mycroft.mic.mute', handle_mic_mute)
    bus.on('mycroft.mic.unmute', handle_mic_unmute)
    bus.on('mycroft.mic.get_status', handle_mic_get_status)
    bus.on("mycroft.paired", handle_paired)
    bus.on('recognizer_loop:audio_output_start', handle_audio_start)
    bus.on('recognizer_loop:audio_output_end', handle_audio_end)
    bus.on('mycroft.stop', handle_stop)

    create_daemon(bus.run_forever)
    create_daemon(loop.run)

    wait_for_exit_signal()
class Enclosure(object):
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """

    _last_internet_notification = 0

    def __init__(self):
        self.ws = WebsocketClient()
        ConfigurationManager.init(self.ws)
        self.config = ConfigurationManager.instance().get("enclosure")
        self.__init_serial()
        self.reader = EnclosureReader(self.serial, self.ws)
        self.writer = EnclosureWriter(self.serial, self.ws)

        # Send a message to the Arduino across the serial line asking
        # for a reply with version info.
        self.writer.write("system.version")
        # When the Arduino responds, it will generate this message
        self.ws.on("enclosure.started", self.on_arduino_responded)

        self.arduino_responded = False

        # Start a 5 second timer.  If the serial port hasn't received
        # any acknowledgement of the "system.version" within those
        # 5 seconds, assume there is nothing on the other end (e.g.
        # we aren't running a Mark 1 with an Arduino)
        Timer(5, self.check_for_response).start()

        # Notifications from mycroft-core
        self.ws.on("enclosure.notify.no_internet", self.on_no_internet)

    def on_arduino_responded(self, event=None):
        self.eyes = EnclosureEyes(self.ws, self.writer)
        self.mouth = EnclosureMouth(self.ws, self.writer)
        self.system = EnclosureArduino(self.ws, self.writer)
        self.weather = EnclosureWeather(self.ws, self.writer)
        self.__register_events()
        self.__reset()
        self.arduino_responded = True

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self._do_net_check).start()

    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time()-Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()

        # TODO: This should go into EnclosureMark1 subclass of Enclosure.
        if has_been_paired():
            # Handle the translation within that code.
            self.ws.emit(Message("speak", {
                'utterance': "This device is not connected to the Internet. "
                             "Either plug in a network cable or hold the "
                             "button on top for two seconds, then select "
                             "wifi from the menu"}))
        else:
            # enter wifi-setup mode automatically
            self.ws.emit(Message("mycroft.wifi.start"))

    def __init_serial(self):
        try:
            self.port = self.config.get("port")
            self.rate = self.config.get("rate")
            self.timeout = self.config.get("timeout")
            self.serial = serial.serial_for_url(
                url=self.port, baudrate=self.rate, timeout=self.timeout)
            LOG.info("Connected to: %s rate: %s timeout: %s" %
                     (self.port, self.rate, self.timeout))
        except:
            LOG.error("Impossible to connect to serial port: " + self.port)
            raise

    def __register_events(self):
        self.ws.on('enclosure.mouth.events.activate',
                   self.__register_mouth_events)
        self.ws.on('enclosure.mouth.events.deactivate',
                   self.__remove_mouth_events)
        self.ws.on('enclosure.reset',
                   self.__reset)
        self.__register_mouth_events()

    def __register_mouth_events(self, event=None):
        self.ws.on('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.on('recognizer_loop:record_end', self.mouth.reset)
        self.ws.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.ws.on('recognizer_loop:audio_output_end', self.mouth.reset)

    def __remove_mouth_events(self, event=None):
        self.ws.remove('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.remove('recognizer_loop:record_end', self.mouth.reset)
        self.ws.remove('recognizer_loop:audio_output_start',
                       self.mouth.talk)
        self.ws.remove('recognizer_loop:audio_output_end',
                       self.mouth.reset)

    def __reset(self, event=None):
        # Reset both the mouth and the eye elements to indicate the unit is
        # ready for input.
        self.writer.write("eyes.reset")
        self.writer.write("mouth.reset")

    def speak(self, text):
        self.ws.emit(Message("speak", {'utterance': text}))

    def run(self):
        try:
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def check_for_response(self):
        if not self.arduino_responded:
            # There is nothing on the other end of the serial port
            # close these serial-port readers and this process
            self.writer.stop()
            self.reader.stop()
            self.serial.close()
            self.ws.close()

    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. Enclosure_Mark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.ws.emit(Message("speak", {
                    'utterance': "This unit is not connected to the Internet."
                                 " Either plug in a network cable or hold the "
                                 "button on top for two seconds, then select "
                                 "wifi from the menu"
                    }))
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in Enclosure_Mark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.ws.emit(Message("mycroft.mic.mute", None))

                # Kick off wifi-setup automatically
                self.ws.emit(Message("mycroft.wifi.start",
                                     {'msg': "Hello I am Mycroft, your new "
                                      "assistant.  To assist you I need to be "
                                      "connected to the internet.  You can "
                                      "either plug me in with a network cable,"
                                      " or use wifi.  To setup wifi ",
                                      'allow_timeout': False}))
Esempio n. 41
0
def gui_main(stdscr):
    global scr
    global bus
    global line
    global log_line_lr_scroll
    global longest_visible_line
    global find_str
    global last_key
    global history
    global screen_lock

    scr = stdscr
    init_screen()
    scr.keypad(1)
    scr.notimeout(1)

    bus = WebsocketClient()  # Mycroft messagebus connection
    bus.on('speak', handle_speak)
    bus.on('message', handle_message)
    bus.on('recognizer_loop:utterance', handle_utterance)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    gui_thread = ScreenDrawThread()
    gui_thread.setDaemon(True)  # this thread won't prevent prog from exiting
    gui_thread.start()

    hist_idx = -1  # index, from the bottom
    c = 0
    try:
        while True:
            set_screen_dirty()

            try:
                c = scr.get_wch()  # unicode char or int for special keys
            except KeyboardInterrupt:
                # User hit Ctrl+C to quit
                if find_str:
                    # End the find session
                    find_str = None
                    rebuild_filtered_log()
                    continue  # Consumed the Ctrl+C, get next character
                else:
                    c = 24  # treat as Ctrl+X (Exit)
            except curses.error:
                # This happens in odd cases, such as when you Ctrl+Z suspend
                # the CLI and then resume.  Curses fails on get_wch().
                continue

            if isinstance(c, int):
                code = c
            else:
                code = ord(c)

            # Convert VT100 ESC codes generated by some terminals
            if code == 27:
                # NOTE:  Not sure exactly why, but the screen can get corrupted
                # if we draw to the screen while doing a scr.getch().  So
                # lock screen updates until the VT100 sequence has been
                # completely read.
                with screen_lock:
                    scr.timeout(0)
                    c1 = -1
                    start = time.time()
                    while c1 == -1:
                        c1 = scr.getch()
                        if time.time()-start > 1:
                            break  # 1 second timeout waiting for ESC code

                    c2 = -1
                    while c2 == -1:
                        c2 = scr.getch()
                        if time.time()-start > 1:  # 1 second timeout
                            break  # 1 second timeout waiting for ESC code
                    scr.timeout(-1)

                if c1 == 79 and c2 == 120:
                    c = curses.KEY_UP
                elif c1 == 79 and c2 == 116:
                    c = curses.KEY_LEFT
                elif c1 == 79 and c2 == 114:
                    c = curses.KEY_DOWN
                elif c1 == 79 and c2 == 118:
                    c = curses.KEY_RIGHT
                elif c1 == 79 and c2 == 121:
                    c = curses.KEY_PPAGE  # aka PgUp
                elif c1 == 79 and c2 == 115:
                    c = curses.KEY_NPAGE  # aka PgDn
                elif c1 == 79 and c2 == 119:
                    c = curses.KEY_HOME
                elif c1 == 79 and c2 == 113:
                    c = curses.KEY_END
                else:
                    c = c1

                if c1 != -1:
                    last_key = str(c) + ",ESC+" + str(c1) + "+" + str(c2)
                    code = c
                else:
                    last_key = "ESC"
            else:
                if code < 33:
                    last_key = str(code)
                else:
                    last_key = str(code)

            if code == 27:    # Hitting ESC twice clears the entry line
                hist_idx = -1
                line = ""
            elif c == curses.KEY_RESIZE:
                # Generated by Curses when window/screen has been resized
                y, x = scr.getmaxyx()
                curses.resizeterm(y, x)

                # resizeterm() causes another curses.KEY_RESIZE, so
                # we need to capture that to prevent a loop of resizes
                c = scr.get_wch()
            elif screen_mode == SCR_HELP:
                # in Help mode, any key goes to next page
                show_next_help()
                continue
            elif c == '\n' or code == 10 or code == 13 or code == 343:
                # ENTER sends the typed line to be processed by Mycroft
                if line == "":
                    continue

                if line[:1] == ":":
                    # Lines typed like ":help" are 'commands'
                    if handle_cmd(line[1:]) == 1:
                        break
                else:
                    # Treat this as an utterance
                    bus.emit(Message("recognizer_loop:utterance",
                                     {'utterances': [line.strip()],
                                      'lang': 'en-us'}))
                hist_idx = -1
                line = ""
            elif code == 16 or code == 545:  # Ctrl+P or Ctrl+Left (Previous)
                # Move up the history stack
                hist_idx = clamp(hist_idx + 1, -1, len(history) - 1)
                if hist_idx >= 0:
                    line = history[len(history) - hist_idx - 1]
                else:
                    line = ""
            elif code == 14 or code == 560:  # Ctrl+N or Ctrl+Right (Next)
                # Move down the history stack
                hist_idx = clamp(hist_idx - 1, -1, len(history) - 1)
                if hist_idx >= 0:
                    line = history[len(history) - hist_idx - 1]
                else:
                    line = ""
            elif c == curses.KEY_LEFT:
                # scroll long log lines left
                log_line_lr_scroll += curses.COLS // 4
            elif c == curses.KEY_RIGHT:
                # scroll long log lines right
                log_line_lr_scroll -= curses.COLS // 4
                if log_line_lr_scroll < 0:
                    log_line_lr_scroll = 0
            elif c == curses.KEY_HOME:
                # HOME scrolls log lines all the way to the start
                log_line_lr_scroll = longest_visible_line
            elif c == curses.KEY_END:
                # END scrolls log lines all the way to the end
                log_line_lr_scroll = 0
            elif c == curses.KEY_UP:
                scroll_log(False, 1)
            elif c == curses.KEY_DOWN:
                scroll_log(True, 1)
            elif c == curses.KEY_NPAGE:  # aka PgDn
                # PgDn to go down a page in the logs
                scroll_log(True)
            elif c == curses.KEY_PPAGE:  # aka PgUp
                # PgUp to go up a page in the logs
                scroll_log(False)
            elif code == 2 or code == 550:  # Ctrl+B or Ctrl+PgDn
                scroll_log(True, max_log_lines)
            elif code == 20 or code == 555:  # Ctrl+T or Ctrl+PgUp
                scroll_log(False, max_log_lines)
            elif code == curses.KEY_BACKSPACE or code == 127:
                # Backspace to erase a character in the utterance
                line = line[:-1]
            elif code == 6:  # Ctrl+F (Find)
                line = ":find "
            elif code == 18:  # Ctrl+R (Redraw)
                scr.erase()
            elif code == 24:  # Ctrl+X (Exit)
                if find_str:
                    # End the find session
                    find_str = None
                    rebuild_filtered_log()
                else:
                    break
            elif code > 31 and isinstance(c, str):
                # Accept typed character in the utterance
                line += c

    finally:
        scr.erase()
        scr.refresh()
        scr = None
Esempio n. 42
0
class Enclosure:
    def __init__(self):
        # Establish Enclosure's websocket connection to the messagebus
        self.bus = WebsocketClient()

        # Load full config
        Configuration.init(self.bus)
        config = Configuration.get()

        self.lang = config['lang']
        self.config = config.get("enclosure")
        self.global_config = config

        # This datastore holds the data associated with the GUI provider. Data
        # is stored in Namespaces, so you can have:
        # self.datastore["namespace"]["name"] = value
        # Typically the namespace is a meaningless identifier, but there is a
        # special "SYSTEM" namespace.
        self.datastore = {}

        # self.loaded is a list, each element consists of a namespace named
        # tuple.
        # The namespace namedtuple has the properties "name" and "pages"
        # The name contains the namespace name as a string and pages is a
        # mutable list of loaded pages.
        #
        # [Namespace name, [List of loaded qml pages]]
        # [
        # ["SKILL_NAME", ["page1.qml, "page2.qml", ... , "pageN.qml"]
        # [...]
        # ]
        self.loaded = []  # list of lists in order.
        self.explicit_move = True  # Set to true to send reorder commands

        # Listen for new GUI clients to announce themselves on the main bus
        self.GUIs = {}      # GUIs, either local or remote
        self.active_namespaces = []
        self.bus.on("mycroft.gui.connected", self.on_gui_client_connected)
        self.register_gui_handlers()

        # First send any data:
        self.bus.on("gui.value.set", self.on_gui_set_value)
        self.bus.on("gui.page.show", self.on_gui_show_page)
        self.bus.on("gui.page.delete", self.on_gui_delete_page)
        self.bus.on("gui.clear.namespace", self.on_gui_delete_namespace)
        self.bus.on("gui.event.send", self.on_gui_send_event)

    def run(self):
        try:
            self.bus.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    ######################################################################
    # GUI client API

    def send(self, *args, **kwargs):
        """ Send to all registered GUIs. """
        for gui in self.GUIs.values():
            if gui.socket:
                gui.socket.send(*args, **kwargs)
            else:
                LOG.error('GUI connection {} has no socket!'.format(gui))

    def on_gui_send_event(self, message):
        """ Send an event to the GUIs. """
        try:
            data = {'type': 'mycroft.events.triggered',
                    'namespace': message.data.get('__from'),
                    'event_name': message.data.get('event_name'),
                    'params': message.data.get('params')}
            self.send(data)
        except Exception as e:
            LOG.error('Could not send event ({})'.format(repr(e)))

    def on_gui_set_value(self, message):
        data = message.data
        namespace = data.get("__from", "")

        # Pass these values on to the GUI renderers
        for key in data:
            if key not in RESERVED_KEYS:
                try:
                    self.set(namespace, key, data[key])
                except Exception as e:
                    LOG.exception(repr(e))

    def set(self, namespace, name, value):
        """ Perform the send of the values to the connected GUIs. """
        if namespace not in self.datastore:
            self.datastore[namespace] = {}
        if self.datastore[namespace].get(name) != value:
            self.datastore[namespace][name] = value

            # If the namespace is loaded send data to GUI
            if namespace in [l.name for l in self.loaded]:
                msg = {"type": "mycroft.session.set",
                       "namespace": namespace,
                       "data": {name: value}}
                self.send(msg)

    def on_gui_delete_page(self, message):
        """ Bus handler for removing pages. """
        page, namespace, _ = _get_page_data(message)
        try:
            self.remove_pages(namespace, page)
        except Exception as e:
            LOG.exception(repr(e))

    def on_gui_delete_namespace(self, message):
        """ Bus handler for removing namespace. """
        try:
            namespace = message.data['__from']
            self.remove_namespace(namespace)
        except Exception as e:
            LOG.exception(repr(e))

    def on_gui_show_page(self, message):
        try:
            page, namespace, index = _get_page_data(message)
            # Pass the request to the GUI(s) to pull up a page template
            self.show(namespace, page, index)
        except Exception as e:
            LOG.exception(repr(e))

    def __find_namespace(self, namespace):
        for i, skill in enumerate(self.loaded):
            if skill[0] == namespace:
                return i
        return None

    def __insert_pages(self, namespace, pages):
        """ Insert pages into the namespace

        Args:
            namespace (str): Namespace to add to
            pages (list):    Pages (str) to insert
        """
        LOG.debug("Inserting new pages")
        if not isinstance(pages, list):
            raise ValueError('Argument must be list of pages')

        self.send({"type": "mycroft.gui.list.insert",
                   "namespace": namespace,
                   "position": len(self.loaded[0].pages),
                   "data": [{"url": p} for p in pages]
                   })
        # Insert the pages into local reprensentation as well.
        self.loaded[0].pages += pages

    def __remove_page(self, namespace, pos):
        """ Delete page.

        Args:
            namespace (str): Namespace to remove from
            pos (int):      Page position to remove
        """
        LOG.debug("Deleting {} from {}".format(pos, namespace))
        self.send({"type": "mycroft.gui.list.remove",
                   "namespace": namespace,
                   "position": pos,
                   "items_number": 1
                   })
        # Remove the page from the local reprensentation as well.
        self.loaded[0].pages.pop(pos)

    def __insert_new_namespace(self, namespace, pages):
        """ Insert new namespace and pages.

        This first sends a message adding a new namespace at the
        highest priority (position 0 in the namespace stack)

        Args:
            namespace (str):  The skill namespace to create
            pages (str):      Pages to insert (name matches QML)
        """
        LOG.debug("Inserting new namespace")
        self.send({"type": "mycroft.session.list.insert",
                   "namespace": "mycroft.system.active_skills",
                   "position": 0,
                   "data": [{"skill_id": namespace}]
                   })

        # Load any already stored Data
        data = self.datastore.get(namespace, {})
        for key in data:
            msg = {"type": "mycroft.session.set",
                   "namespace": namespace,
                   "data": {key: data[key]}}
            self.send(msg)

        LOG.debug("Inserting new page")
        self.send({"type": "mycroft.gui.list.insert",
                   "namespace": namespace,
                   "position": 0,
                   "data": [{"url": p} for p in pages]
                   })
        # Make sure the local copy is updated
        self.loaded.insert(0, Namespace(namespace, pages))

    def __move_namespace(self, from_pos, to_pos):
        """ Move an existing namespace to a new position in the stack.

        Args:
            from_pos (int): Position in the stack to move from
            to_pos (int): Position to move to
        """
        LOG.debug("Activating existing namespace")
        # Seems like the namespace is moved to the top automatically when
        # a page change is done. Deactivating this for now.
        if self.explicit_move:
            LOG.debug("move {} to {}".format(from_pos, to_pos))
            self.send({"type": "mycroft.session.list.move",
                       "namespace": "mycroft.system.active_skills",
                       "from": from_pos, "to": to_pos,
                       "items_number": 1})
        # Move the local representation of the skill from current
        # position to position 0.
        self.loaded.insert(to_pos, self.loaded.pop(from_pos))

    def __switch_page(self, namespace, pages):
        """ Switch page to an already loaded page.

        Args:
            pages (list): pages (str) to switch to
            namespace (str):  skill namespace
        """
        try:
            num = self.loaded[0].pages.index(pages[0])
        except Exception as e:
            LOG.exception(repr(e))
            num = 0

        LOG.debug('Switching to already loaded page at '
                  'index {} in namespace {}'.format(num, namespace))
        self.send({"type": "mycroft.events.triggered",
                   "namespace": namespace,
                   "event_name": "page_gained_focus",
                   "data": {"number": num}})

    def show(self, namespace, page, index):
        """ Show a page and load it as needed.

        Args:
            page (str or list): page(s) to show
            namespace (str):  skill namespace
            index (int): ??? TODO: Unused in code ???

        TODO: - Update sync to match.
              - Separate into multiple functions/methods
        """

        LOG.debug("GUIConnection activating: " + namespace)
        pages = page if isinstance(page, list) else [page]

        # find namespace among loaded namespaces
        try:
            index = self.__find_namespace(namespace)
            if index is None:
                # This namespace doesn't exist, insert them first so they're
                # shown.
                self.__insert_new_namespace(namespace, pages)
                return
            else:  # Namespace exists
                if index > 0:
                    # Namespace is inactive, activate it by moving it to
                    # position 0
                    self.__move_namespace(index, 0)

                # Find if any new pages needs to be inserted
                new_pages = [p for p in pages if p not in self.loaded[0].pages]
                if new_pages:
                    self.__insert_pages(namespace, new_pages)
                else:
                    # No new pages, just switch
                    self.__switch_page(namespace, pages)
        except Exception as e:
            LOG.exception(repr(e))

    def remove_namespace(self, namespace):
        """ Remove namespace.

        Args:
            namespace (str): namespace to remove
        """
        index = self.__find_namespace(namespace)
        if index is None:
            return
        else:
            LOG.debug("Removing namespace {} at {}".format(namespace, index))
            self.send({"type": "mycroft.session.list.remove",
                       "namespace": "mycroft.system.active_skills",
                       "position": index,
                       "items_number": 1
                       })
            # Remove namespace from loaded namespaces
            self.loaded.pop(index)

    def remove_pages(self, namespace, pages):
        """ Remove the listed pages from the provided namespace.

        Args:
            namespace (str):    The namespace to modify
            pages (list):       List of page names (str) to delete
        """
        try:
            index = self.__find_namespace(namespace)
            if index is None:
                return
            else:
                # Remove any pages that doesn't exist in the namespace
                pages = [p for p in pages if p in self.loaded[index].pages]
                # Make sure to remove pages from the back
                indexes = [self.loaded[index].pages.index(p) for p in pages]
                indexes = sorted(indexes)
                indexes.reverse()
                for page_index in indexes:
                    self.__remove_page(namespace, page_index)
        except Exception as e:
            LOG.exception(repr(e))

    ######################################################################
    # GUI client socket
    #
    # The basic mechanism is:
    # 1) GUI client announces itself on the main messagebus
    # 2) Mycroft prepares a port for a socket connection to this GUI
    # 3) The port is announced over the messagebus
    # 4) The GUI connects on the socket
    # 5) Connection persists for graphical interaction indefinitely
    #
    # If the connection is lost, it must be renegotiated and restarted.
    def on_gui_client_connected(self, message):
        # GUI has announced presence
        LOG.debug("on_gui_client_connected")
        gui_id = message.data.get("gui_id")

        # Spin up a new communication socket for this GUI
        if gui_id in self.GUIs:
            # TODO: Close it?
            pass
        self.GUIs[gui_id] = GUIConnection(gui_id, self.global_config,
                                          self.callback_disconnect, self)
        LOG.debug("Heard announcement from gui_id: {}".format(gui_id))

        # Announce connection, the GUI should connect on it soon
        self.bus.emit(Message("mycroft.gui.port",
                              {"port": self.GUIs[gui_id].port,
                               "gui_id": gui_id}))

    def callback_disconnect(self, gui_id):
        LOG.info("Disconnecting!")
        # TODO: Whatever is needed to kill the websocket instance
        LOG.info(self.GUIs.keys())
        LOG.info('deleting: {}'.format(gui_id))
        if gui_id in self.GUIs:
            del self.GUIs[gui_id]
        else:
            LOG.warning('ID doesn\'t exist')

    def register_gui_handlers(self):
        # TODO: Register handlers for standard (Mark 1) events
        # self.bus.on('enclosure.eyes.on', self.on)
        # self.bus.on('enclosure.eyes.off', self.off)
        # self.bus.on('enclosure.eyes.blink', self.blink)
        # self.bus.on('enclosure.eyes.narrow', self.narrow)
        # self.bus.on('enclosure.eyes.look', self.look)
        # self.bus.on('enclosure.eyes.color', self.color)
        # self.bus.on('enclosure.eyes.level', self.brightness)
        # self.bus.on('enclosure.eyes.volume', self.volume)
        # self.bus.on('enclosure.eyes.spin', self.spin)
        # self.bus.on('enclosure.eyes.timedspin', self.timed_spin)
        # self.bus.on('enclosure.eyes.reset', self.reset)
        # self.bus.on('enclosure.eyes.setpixel', self.set_pixel)
        # self.bus.on('enclosure.eyes.fill', self.fill)

        # self.bus.on('enclosure.mouth.reset', self.reset)
        # self.bus.on('enclosure.mouth.talk', self.talk)
        # self.bus.on('enclosure.mouth.think', self.think)
        # self.bus.on('enclosure.mouth.listen', self.listen)
        # self.bus.on('enclosure.mouth.smile', self.smile)
        # self.bus.on('enclosure.mouth.viseme', self.viseme)
        # self.bus.on('enclosure.mouth.text', self.text)
        # self.bus.on('enclosure.mouth.display', self.display)
        # self.bus.on('enclosure.mouth.display_image', self.display_image)
        # self.bus.on('enclosure.weather.display', self.display_weather)

        # self.bus.on('recognizer_loop:record_begin', self.mouth.listen)
        # self.bus.on('recognizer_loop:record_end', self.mouth.reset)
        # self.bus.on('recognizer_loop:audio_output_start', self.mouth.talk)
        # self.bus.on('recognizer_loop:audio_output_end', self.mouth.reset)
        pass
Esempio n. 43
0
class TestMessagebusMethods(unittest.TestCase):
    """This class is for testing the messsagebus.

    It currently only tests send and receive.  The tests could include
    more.
    """
    def setUp(self):
        """
        This sets up for testing the message buss

        This requires starting the mycroft service and creating two
        WebsocketClient object to talk with eachother.  Not this is
        threaded and will require cleanup
        """
        # start the mycroft service. and get the pid of the script.
        self.pid = Popen(["python", "mycroft/messagebus/service/main.py"]).pid
        # delay to allow the service to start up.
        time.sleep(10)
        # Create the two web clients
        self.ws1 = WebsocketClient()
        self.ws2 = WebsocketClient()
        # init the flags for handler's
        self.handle1 = False
        self.handle2 = False
        # Start threads to handle websockets
        Thread(target=self.ws1.run_forever).start()
        Thread(target=self.ws2.run_forever).start()
        # Sleep to give the websockets to startup before adding handlers
        time.sleep(10)
        # Setup handlers for each of the messages.
        self.ws1.on('ws1.message', self.onHandle1)
        self.ws2.on('ws2.message', self.onHandle2)

    def onHandle1(self, event):
        """This is the handler for ws1.message

        This for now simply sets a flag to true when received.

        Args:
            event(Message): this is the message received
        """
        self.handle1 = True

    def onHandle2(self, event):
        """This is the handler for ws2.message

        This for now simply sets a flag to true when received.

        Args:
            event(Message): this is the message received
        """
        self.handle2 = True

    def tearDown(self):
        """This is the clean up for the tests

        This will close the websockets ending the threads then kill the
        mycroft service that was started in setUp.
        """
        self.ws1.close()
        self.ws2.close()
        retcode = call(["kill", "-9", str(self.pid)])

    def test_ClientServer(self):
        """This is the test to send a message from each of the websockets
        to the other.
        """
        # Send the messages
        self.ws2.emit(Message('ws1.message'))
        self.ws1.emit(Message('ws2.message'))
        # allow time for messages to be processed
        time.sleep(10)
        # Check that both of the handlers were called.
        self.assertTrue(self.handle1)
        self.assertTrue(self.handle2)
Esempio n. 44
0
class Enclosure(object):
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """

    _last_internet_notification = 0

    def __init__(self):
        self.ws = WebsocketClient()
        ConfigurationManager.init(self.ws)
        self.config = ConfigurationManager.get().get("enclosure")
        self.__init_serial()
        self.reader = EnclosureReader(self.serial, self.ws)
        self.writer = EnclosureWriter(self.serial, self.ws)

        # Send a message to the Arduino across the serial line asking
        # for a reply with version info.
        self.writer.write("system.version")
        # When the Arduino responds, it will generate this message
        self.ws.on("enclosure.started", self.on_arduino_responded)

        self.arduino_responded = False

        # Start a 5 second timer.  If the serial port hasn't received
        # any acknowledgement of the "system.version" within those
        # 5 seconds, assume there is nothing on the other end (e.g.
        # we aren't running a Mark 1 with an Arduino)
        Timer(5, self.check_for_response).start()

        # Notifications from mycroft-core
        self.ws.on("enclosure.notify.no_internet", self.on_no_internet)

    def on_arduino_responded(self, event=None):
        self.eyes = EnclosureEyes(self.ws, self.writer)
        self.mouth = EnclosureMouth(self.ws, self.writer)
        self.system = EnclosureArduino(self.ws, self.writer)
        self.weather = EnclosureWeather(self.ws, self.writer)
        self.__register_events()
        self.__reset()
        self.arduino_responded = True

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self.on_no_internet).start()

    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time()-Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()

        # TODO: This should go into EnclosureMark1 subclass of Enclosure.
        # Handle the translation within that code.
        self.ws.emit(Message("speak", {
            'utterance': "This device is not connected to the Internet. "
                         "Either plug in a network cable or hold the button "
                         "on top for two seconds, then select wifi from the "
                         "menu"}))

    def __init_serial(self):
        try:
            self.port = self.config.get("port")
            self.rate = self.config.get("rate")
            self.timeout = self.config.get("timeout")
            self.serial = serial.serial_for_url(
                url=self.port, baudrate=self.rate, timeout=self.timeout)
            LOG.info("Connected to: %s rate: %s timeout: %s" %
                     (self.port, self.rate, self.timeout))
        except:
            LOG.error("Impossible to connect to serial port: " + self.port)
            raise

    def __register_events(self):
        self.ws.on('enclosure.mouth.events.activate',
                   self.__register_mouth_events)
        self.ws.on('enclosure.mouth.events.deactivate',
                   self.__remove_mouth_events)
        self.ws.on('enclosure.reset',
                   self.__reset)
        self.__register_mouth_events()

    def __register_mouth_events(self, event=None):
        self.ws.on('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.on('recognizer_loop:record_end', self.mouth.reset)
        self.ws.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.ws.on('recognizer_loop:audio_output_end', self.mouth.reset)

    def __remove_mouth_events(self, event=None):
        self.ws.remove('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.remove('recognizer_loop:record_end', self.mouth.reset)
        self.ws.remove('recognizer_loop:audio_output_start',
                       self.mouth.talk)
        self.ws.remove('recognizer_loop:audio_output_end',
                       self.mouth.reset)

    def __reset(self, event=None):
        # Reset both the mouth and the eye elements to indicate the unit is
        # ready for input.
        self.writer.write("eyes.reset")
        self.writer.write("mouth.reset")

    def speak(self, text):
        self.ws.emit(Message("speak", {'utterance': text}))

    def run(self):
        try:
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def check_for_response(self):
        if not self.arduino_responded:
            # There is nothing on the other end of the serial port
            # close these serial-port readers and this process
            self.writer.stop()
            self.reader.stop()
            self.serial.close()
            self.ws.close()
Esempio n. 45
0
class TestMessagebusMethods(unittest.TestCase):
    """This class is for testing the messsagebus.

    It currently only tests send and receive.  The tests could include
    more.
    """

    def setUp(self):
        """
        This sets up for testing the message buss

        This requires starting the mycroft service and creating two
        WebsocketClient object to talk with eachother.  Not this is
        threaded and will require cleanup
        """
        # start the mycroft service. and get the pid of the script.
        self.pid = Popen(["python", "mycroft/messagebus/service/main.py"]).pid
        # Create the two web clients
        self.ws1 = WebsocketClient()
        self.ws2 = WebsocketClient()
        # init the flags for handler's
        self.handle1 = False
        self.handle2 = False
        # Start threads to handle websockets
        Thread(target=self.ws1.run_forever).start()
        Thread(target=self.ws2.run_forever).start()
        # Setup handlers for each of the messages.
        self.ws1.on('ws1.message', self.onHandle1)
        self.ws2.on('ws2.message', self.onHandle2)

    def onHandle1(self, event):
        """This is the handler for ws1.message

        This for now simply sets a flag to true when received.

        Args:
            event(Message): this is the message received
        """
        self.handle1 = True

    def onHandle2(self, event):
        """This is the handler for ws2.message

        This for now simply sets a flag to true when received.

        Args:
            event(Message): this is the message received
        """
        self.handle2 = True

    def tearDown(self):
        """This is the clean up for the tests

        This will close the websockets ending the threads then kill the
        mycroft service that was started in setUp.
        """
        self.ws1.close()
        self.ws2.close()
        retcode = call(["kill", "-9", str(self.pid)])

    def test_ClientServer(self):
        """This is the test to send a message from each of the websockets
        to the other.
        """
        # Send the messages
        self.ws2.emit(Message('ws1.message'))
        self.ws1.emit(Message('ws2.message'))
        # allow time for messages to be processed
        time.sleep(0.2)
        # Check that both of the handlers were called.
        self.assertTrue(self.handle1)
        self.assertTrue(self.handle2)
Esempio n. 46
0
class Enclosure():
    def __init__(self):
        # Establish Enclosure's websocket connection to the messagebus
        self.bus = WebsocketClient()

        # Load full config
        Configuration.init(self.bus)
        config = Configuration.get()

        self.lang = config['lang']
        self.config = config.get("enclosure")
        self.global_config = config

        # Listen for new GUI clients to announce themselves on the main bus
        self.GUIs = {}  # GUIs, either local or remote
        self.active_namespaces = []
        self.bus.on("mycroft.gui.connected", self.on_gui_client_connected)
        self.register_gui_handlers()

        # First send any data:
        self.bus.on("gui.value.set", self.on_gui_set_value)
        self.bus.on("gui.page.show", self.on_gui_show_page)

    def run(self):
        try:
            self.bus.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    ######################################################################
    # GUI client API

    def _gui_activate(self, namespace, move_to_top=False):
        if not namespace:
            return

        if namespace not in self.active_namespaces:
            if move_to_top:
                self.active_namespaces.insert(0, namespace)
            else:
                self.active_namespaces.append(namespace)
        elif move_to_top:
            self.active_namespaces.remove(namespace)
            self.active_namespaces.insert(0, namespace)
        # TODO: Keep a timestamp and auto-cull?

    def on_gui_set_value(self, message):
        data = message.data
        namespace = data.get("__from", "")

        self._gui_activate(namespace)

        # Pass these values on to the GUI renderers
        for id in self.GUIs:
            for key in data:
                if key != "__from":
                    self.GUIs[id].set(namespace, key, data[key])

    def on_gui_show_page(self, message):
        data = message.data

        # Note:  'page' can be either a string or a list of strings
        if 'page' not in data:
            return
        if 'index' in data:
            index = data['index']
        else:
            index = 0
        namespace = data.get("__from", "")
        self._gui_activate(namespace, move_to_top=True)

        # Pass the request to the GUI(s) to pull up a page template
        for id in self.GUIs:
            self.GUIs[id].show(namespace, data['page'], index)

    ######################################################################
    # GUI client socket
    #
    # The basic mechanism is:
    # 1) GUI client announces itself on the main messagebus
    # 2) Mycroft prepares a port for a socket connection to this GUI
    # 3) The port is announced over the messagebus
    # 4) The GUI connects on the socket
    # 5) Connection persists for graphical interaction indefinitely
    #
    # If the connection is lost, it must be renegotiated and restarted.

    def on_gui_client_connected(self, message):
        # GUI has announced presence
        DEBUG("on_gui_client_connected")
        gui_id = message.data.get("gui_id")

        # Spin up a new communication socket for this GUI
        if gui_id in self.GUIs:
            # TODO: Close it?
            pass
        self.GUIs[gui_id] = GUIConnection(gui_id, self.global_config,
                                          self.callback_disconnect, self)
        DEBUG("Heard announcement from gui_id: {}".format(gui_id))

        # Announce connection, the GUI should connect on it soon
        self.bus.emit(
            Message("mycroft.gui.port", {
                "port": self.GUIs[gui_id].port,
                "gui_id": gui_id
            }))

    def callback_disconnect(self, gui_id):
        DEBUG("Disconnecting!")
        # TODO: Whatever is needed to kill the websocket instance
        del self.GUIs[gui_id]

    def register_gui_handlers(self):
        # TODO: Register handlers for standard (Mark 1) events
        # self.bus.on('enclosure.eyes.on', self.on)
        # self.bus.on('enclosure.eyes.off', self.off)
        # self.bus.on('enclosure.eyes.blink', self.blink)
        # self.bus.on('enclosure.eyes.narrow', self.narrow)
        # self.bus.on('enclosure.eyes.look', self.look)
        # self.bus.on('enclosure.eyes.color', self.color)
        # self.bus.on('enclosure.eyes.level', self.brightness)
        # self.bus.on('enclosure.eyes.volume', self.volume)
        # self.bus.on('enclosure.eyes.spin', self.spin)
        # self.bus.on('enclosure.eyes.timedspin', self.timed_spin)
        # self.bus.on('enclosure.eyes.reset', self.reset)
        # self.bus.on('enclosure.eyes.setpixel', self.set_pixel)
        # self.bus.on('enclosure.eyes.fill', self.fill)

        # self.bus.on('enclosure.mouth.reset', self.reset)
        # self.bus.on('enclosure.mouth.talk', self.talk)
        # self.bus.on('enclosure.mouth.think', self.think)
        # self.bus.on('enclosure.mouth.listen', self.listen)
        # self.bus.on('enclosure.mouth.smile', self.smile)
        # self.bus.on('enclosure.mouth.viseme', self.viseme)
        # self.bus.on('enclosure.mouth.text', self.text)
        # self.bus.on('enclosure.mouth.display', self.display)
        # self.bus.on('enclosure.mouth.display_image', self.display_image)
        # self.bus.on('enclosure.weather.display', self.display_weather)

        # self.bus.on('recognizer_loop:record_begin', self.mouth.listen)
        # self.bus.on('recognizer_loop:record_end', self.mouth.reset)
        # self.bus.on('recognizer_loop:audio_output_start', self.mouth.talk)
        # self.bus.on('recognizer_loop:audio_output_end', self.mouth.reset)
        pass
Esempio n. 47
0
class Enclosure(object):
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """

    def __init__(self):
        self.ws = WebsocketClient()
        ConfigurationManager.init(self.ws)
        self.config = ConfigurationManager.get().get("enclosure")
        self.__init_serial()
        self.reader = EnclosureReader(self.serial, self.ws)
        self.writer = EnclosureWriter(self.serial, self.ws)
        self.writer.write("system.version")
        self.ws.on("enclosure.start", self.start)
        self.started = False
        Timer(5, self.stop).start()     # WHY? This at least needs an explaination, this is non-obvious behavior

    def start(self, event=None):
        self.eyes = EnclosureEyes(self.ws, self.writer)
        self.mouth = EnclosureMouth(self.ws, self.writer)
        self.system = EnclosureArduino(self.ws, self.writer)
        self.weather = EnclosureWeather(self.ws, self.writer)
        self.__register_events()
        self.__reset()
        self.started = True

    def __init_serial(self):
        try:
            self.port = self.config.get("port")
            self.rate = self.config.get("rate")
            self.timeout = self.config.get("timeout")
            self.serial = serial.serial_for_url(
                url=self.port, baudrate=self.rate, timeout=self.timeout)
            LOG.info("Connected to: %s rate: %s timeout: %s" %
                     (self.port, self.rate, self.timeout))
        except:
            LOG.error("Impossible to connect to serial port: " + self.port)
            raise

    def __register_events(self):
        self.ws.on('enclosure.mouth.events.activate',
                   self.__register_mouth_events)
        self.ws.on('enclosure.mouth.events.deactivate',
                   self.__remove_mouth_events)
        self.ws.on('enclosure.reset',
                   self.__reset)
        self.__register_mouth_events()

    def __register_mouth_events(self, event=None):
        self.ws.on('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.on('recognizer_loop:record_end', self.mouth.reset)
        self.ws.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.ws.on('recognizer_loop:audio_output_end', self.mouth.reset)

    def __remove_mouth_events(self, event=None):
        self.ws.remove('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.remove('recognizer_loop:record_end', self.mouth.reset)
        self.ws.remove('recognizer_loop:audio_output_start',
                       self.mouth.talk)
        self.ws.remove('recognizer_loop:audio_output_end',
                       self.mouth.reset)

    def __reset(self, event=None):
        # Reset both the mouth and the eye elements to indicate the unit is
        # ready for input.
        self.writer.write("eyes.reset")
        self.writer.write("mouth.reset")

    def speak(self, text):
        self.ws.emit(Message("speak", {'utterance': text}))

    def run(self):
        try:
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def stop(self):
        if not self.started:
            self.writer.stop()
            self.reader.stop()
            self.serial.close()
            self.ws.close()
Esempio n. 48
0
def main():
    global ws
    global loop
    global config
    global tts
    global tts_hash
    lock = PIDLock("voice")
    ws = WebsocketClient()
    config = ConfigurationManager.get()
    tts = TTSFactory.create()
    tts.init(ws)
    tts_hash = config.get('tts')
    ConfigurationManager.init(ws)
    loop = RecognizerLoop()
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('recognizer_loop:record_begin', handle_record_begin)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:record_end', handle_record_end)
    loop.on('speak', handle_speak)
    loop.on('recognizer_loop:no_internet', handle_no_internet)
    ws.on('open', handle_open)
    ws.on('speak', handle_speak)
    ws.on(
        'multi_utterance_intent_failure',
        handle_multi_utterance_intent_failure)
    ws.on('recognizer_loop:sleep', handle_sleep)
    ws.on('recognizer_loop:wake_up', handle_wake_up)
    ws.on('mycroft.mic.mute', handle_mic_mute)
    ws.on('mycroft.mic.unmute', handle_mic_unmute)
    ws.on('mycroft.stop', handle_stop)
    ws.on("mycroft.paired", handle_paired)
    ws.on('recognizer_loop:audio_output_start', handle_audio_start)
    ws.on('recognizer_loop:audio_output_end', handle_audio_end)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    try:
        loop.run()
    except KeyboardInterrupt, e:
        tts.playback.stop()
        tts.playback.join()
        logger.exception(e)
        sys.exit()
class Enclosure(object):
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """
    def __init__(self):
        self.ws = WebsocketClient()
        ConfigurationManager.init(self.ws)
        self.config = ConfigurationManager.get().get("enclosure")
        self.__init_serial()
        self.reader = EnclosureReader(self.serial, self.ws)
        self.writer = EnclosureWriter(self.serial, self.ws)
        self.writer.write("system.version")
        self.ws.on("enclosure.start", self.start)
        self.started = False
        Timer(5, self.stop).start()  # WHY? This at least
        # needs an explanation, this is non-obvious behavior

    def start(self, event=None):
        self.eyes = EnclosureEyes(self.ws, self.writer)
        self.mouth = EnclosureMouth(self.ws, self.writer)
        self.system = EnclosureArduino(self.ws, self.writer)
        self.weather = EnclosureWeather(self.ws, self.writer)
        self.__register_events()
        self.__reset()
        self.started = True

    def __init_serial(self):
        try:
            self.port = self.config.get("port")
            self.rate = self.config.get("rate")
            self.timeout = self.config.get("timeout")
            self.serial = serial.serial_for_url(url=self.port,
                                                baudrate=self.rate,
                                                timeout=self.timeout)
            LOG.info("Connected to: %s rate: %s timeout: %s" %
                     (self.port, self.rate, self.timeout))
        except:
            LOG.error("Impossible to connect to serial port: " + self.port)
            raise

    def __register_events(self):
        self.ws.on('enclosure.mouth.events.activate',
                   self.__register_mouth_events)
        self.ws.on('enclosure.mouth.events.deactivate',
                   self.__remove_mouth_events)
        self.ws.on('enclosure.reset', self.__reset)
        self.__register_mouth_events()

    def __register_mouth_events(self, event=None):
        self.ws.on('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.on('recognizer_loop:record_end', self.mouth.reset)
        self.ws.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.ws.on('recognizer_loop:audio_output_end', self.mouth.reset)

    def __remove_mouth_events(self, event=None):
        self.ws.remove('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.remove('recognizer_loop:record_end', self.mouth.reset)
        self.ws.remove('recognizer_loop:audio_output_start', self.mouth.talk)
        self.ws.remove('recognizer_loop:audio_output_end', self.mouth.reset)

    def __reset(self, event=None):
        # Reset both the mouth and the eye elements to indicate the unit is
        # ready for input.
        self.writer.write("eyes.reset")
        self.writer.write("mouth.reset")

    def speak(self, text):
        self.ws.emit(Message("speak", {'utterance': text}))

    def run(self):
        try:
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def stop(self):
        if not self.started:
            self.writer.stop()
            self.reader.stop()
            self.serial.close()
            self.ws.close()
Esempio n. 50
0
def main():
    global ws
    global loop
    ws = WebsocketClient()
    tts.init(ws)
    ConfigurationManager.init(ws)
    loop = RecognizerLoop()
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('recognizer_loop:record_begin', handle_record_begin)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:record_end', handle_record_end)
    loop.on('speak', handle_speak)
    ws.on('open', handle_open)
    ws.on('speak', handle_speak)
    ws.on('multi_utterance_intent_failure',
          handle_multi_utterance_intent_failure)
    ws.on('recognizer_loop:sleep', handle_sleep)
    ws.on('recognizer_loop:wake_up', handle_wake_up)
    ws.on('mycroft.stop', handle_stop)
    ws.on("mycroft.paired", handle_paired)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    try:
        loop.run()
    except KeyboardInterrupt, e:
        logger.exception(e)
        event_thread.exit()
        sys.exit()
Esempio n. 51
0
def main():
    global ws
    global loop
    global config
    lock = PIDLock("voice")
    ws = WebsocketClient()
    config = Configuration.get()
    Configuration.init(ws)
    loop = RecognizerLoop()
    loop.on('recognizer_loop:utterance', handle_utterance)
    loop.on('speak', handle_speak)
    loop.on('recognizer_loop:record_begin', handle_record_begin)
    loop.on('recognizer_loop:wakeword', handle_wakeword)
    loop.on('recognizer_loop:record_end', handle_record_end)
    loop.on('recognizer_loop:no_internet', handle_no_internet)
    ws.on('open', handle_open)
    ws.on('complete_intent_failure', handle_complete_intent_failure)
    ws.on('recognizer_loop:sleep', handle_sleep)
    ws.on('recognizer_loop:wake_up', handle_wake_up)
    ws.on('mycroft.mic.mute', handle_mic_mute)
    ws.on('mycroft.mic.unmute', handle_mic_unmute)
    ws.on("mycroft.paired", handle_paired)
    ws.on('recognizer_loop:audio_output_start', handle_audio_start)
    ws.on('recognizer_loop:audio_output_end', handle_audio_end)
    ws.on('mycroft.stop', handle_stop)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    try:
        loop.run()
    except KeyboardInterrupt, e:
        LOG.exception(e)
        sys.exit()
Esempio n. 52
0
class Enclosure(object):
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """

    _last_internet_notification = 0

    def __init__(self):
        self.ws = WebsocketClient()
        self.ws.on("open", self.on_ws_open)

        Configuration.init(self.ws)

        global_config = Configuration.get()
        self.lang = global_config['lang']
        self.config = global_config.get("enclosure")

        self.__init_serial()
        self.reader = EnclosureReader(self.serial, self.ws, self.lang)
        self.writer = EnclosureWriter(self.serial, self.ws)

        # initiates the web sockets on display manager
        # NOTE: this is a temporary place to initiate display manager sockets
        initiate_display_manager_ws()

    def on_ws_open(self, event=None):
        # Mark 1 auto-detection:
        #
        # Prepare to receive message when the Arduino responds to the
        # following "system.version"
        self.ws.on("enclosure.started", self.on_arduino_responded)
        self.arduino_responded = False
        # Send a message to the Arduino across the serial line asking
        # for a reply with version info.
        self.writer.write("system.version")
        # Start a 5 second timer.  If the serial port hasn't received
        # any acknowledgement of the "system.version" within those
        # 5 seconds, assume there is nothing on the other end (e.g.
        # we aren't running a Mark 1 with an Arduino)
        Timer(5, self.check_for_response).start()

        # Notifications from mycroft-core
        self.ws.on("enclosure.notify.no_internet", self.on_no_internet)

    def on_arduino_responded(self, event=None):
        self.eyes = EnclosureEyes(self.ws, self.writer)
        self.mouth = EnclosureMouth(self.ws, self.writer)
        self.system = EnclosureArduino(self.ws, self.writer)
        self.weather = EnclosureWeather(self.ws, self.writer)
        self.__register_events()
        self.__reset()
        self.arduino_responded = True

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self._do_net_check).start()

        Timer(60, self._hack_check_for_duplicates).start()

    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time() - Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()

        # TODO: This should go into EnclosureMark1 subclass of Enclosure.
        if has_been_paired():
            # Handle the translation within that code.
            self.ws.emit(Message("speak", {
                'utterance': "This device is not connected to the Internet. "
                             "Either plug in a network cable or hold the "
                             "button on top for two seconds, then select "
                             "wifi from the menu"}))
        else:
            # enter wifi-setup mode automatically
            self.ws.emit(Message('system.wifi.setup', {'lang': self.lang}))

    def __init_serial(self):
        try:
            self.port = self.config.get("port")
            self.rate = self.config.get("rate")
            self.timeout = self.config.get("timeout")
            self.serial = serial.serial_for_url(
                url=self.port, baudrate=self.rate, timeout=self.timeout)
            LOG.info("Connected to: %s rate: %s timeout: %s" %
                     (self.port, self.rate, self.timeout))
        except:
            LOG.error("Impossible to connect to serial port: "+str(self.port))
            raise

    def __register_events(self):
        self.ws.on('enclosure.mouth.events.activate',
                   self.__register_mouth_events)
        self.ws.on('enclosure.mouth.events.deactivate',
                   self.__remove_mouth_events)
        self.ws.on('enclosure.reset',
                   self.__reset)
        self.__register_mouth_events()

    def __register_mouth_events(self, event=None):
        self.ws.on('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.on('recognizer_loop:record_end', self.mouth.reset)
        self.ws.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.ws.on('recognizer_loop:audio_output_end', self.mouth.reset)

    def __remove_mouth_events(self, event=None):
        self.ws.remove('recognizer_loop:record_begin', self.mouth.listen)
        self.ws.remove('recognizer_loop:record_end', self.mouth.reset)
        self.ws.remove('recognizer_loop:audio_output_start',
                       self.mouth.talk)
        self.ws.remove('recognizer_loop:audio_output_end',
                       self.mouth.reset)

    def __reset(self, event=None):
        # Reset both the mouth and the eye elements to indicate the unit is
        # ready for input.
        self.writer.write("eyes.reset")
        self.writer.write("mouth.reset")

    def speak(self, text):
        self.ws.emit(Message("speak", {'utterance': text}))

    def run(self):
        try:
            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()

    def check_for_response(self):
        if not self.arduino_responded:
            # There is nothing on the other end of the serial port
            # close these serial-port readers and this process
            self.writer.stop()
            self.reader.stop()
            self.serial.close()
            self.ws.close()

    def _handle_pairing_complete(self, Message):
        """
            Handler for 'mycroft.paired', unmutes the mic after the pairing is
            complete.
        """
        self.ws.emit(Message("mycroft.mic.unmute"))

    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. Enclosure_Mark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.speak("This unit is not connected to the Internet. "
                           "Either plug in a network cable or hold the "
                           "button on top for two seconds, then select "
                           "wifi from the menu")
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in Enclosure_Mark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.ws.emit(Message("mycroft.mic.mute"))
                # Setup handler to unmute mic at the end of on boarding
                # i.e. after pairing is complete
                self.ws.once('mycroft.paired', self._handle_pairing_complete)

                self.speak(mycroft.dialog.get('mycroft.intro'))
                wait_while_speaking()
                time.sleep(2)  # a pause sounds better than just jumping in

                # Kick off wifi-setup automatically
                data = {'allow_timeout': False, 'lang': self.lang}
                self.ws.emit(Message('system.wifi.setup', data))

    def _hack_check_for_duplicates(self):
        # TEMPORARY HACK:  Look for multiple instance of the
        # mycroft-speech-client and/or mycroft-skills services, which could
        # happen when upgrading a shipping Mark 1 from release 0.8.17 or
        # before.  When found, force the unit to reboot.
        import psutil

        LOG.info("Hack to check for duplicate service instances")

        count_instances = 0
        needs_reboot = False
        for process in psutil.process_iter():
            if process.cmdline() == ['python2.7',
                                     '/usr/local/bin/mycroft-speech-client']:
                count_instances += 1
        if (count_instances > 1):
            LOG.info("Duplicate mycroft-speech-client found")
            needs_reboot = True

        count_instances = 0
        for process in psutil.process_iter():
            if process.cmdline() == ['python2.7',
                                     '/usr/local/bin/mycroft-skills']:
                count_instances += 1
        if (count_instances > 1):
            LOG.info("Duplicate mycroft-skills found")
            needs_reboot = True

        if needs_reboot:
            LOG.info("Hack reboot...")
            self.reader.process("unit.reboot")
            self.ws.emit(Message("enclosure.eyes.spin"))
            self.ws.emit(Message("enclosure.mouth.reset"))
Esempio n. 53
0
def gui_main(stdscr):
    global scr
    global ws
    global line
    global log_line_lr_scroll
    global longest_visible_line
    global find_str
    global last_key

    scr = stdscr
    init_screen()

    ws = WebsocketClient()
    ws.on('speak', handle_speak)
    ws.on('message', handle_message)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    history = []
    hist_idx = -1  # index, from the bottom
    try:
        input = ""
        while True:
            draw_screen()

            c = scr.getch()

            # Convert VT100 ESC codes generated by some terminals
            if c == 27:
                c1 = scr.getch()
                c2 = scr.getch()
                if c1 == 79 and c2 == 120:
                    c = curses.KEY_UP
                elif c1 == 79 and c2 == 116:
                    c = curses.KEY_LEFT
                elif c1 == 79 and c2 == 114:
                    c = curses.KEY_DOWN
                elif c1 == 79 and c2 == 118:
                    c = curses.KEY_RIGHT
                elif c1 == 79 and c2 == 121:
                    c = curses.KEY_PPAGE  # aka PgUp
                elif c1 == 79 and c2 == 115:
                    c = curses.KEY_NPAGE  # aka PgDn
                elif c1 == 79 and c2 == 119:
                    c = curses.KEY_HOME
                elif c1 == 79 and c2 == 113:
                    c = curses.KEY_END
                else:
                    c = c2
                last_key = str(c) + ",ESC+" + str(c1) + "+" + str(c2)
            else:
                last_key = str(c)

            if c == curses.KEY_ENTER or c == 10 or c == 13:
                # ENTER sends the typed line to be processed by Mycroft
                if line == "":
                    continue

                if line[:1] == ":":
                    # Lines typed like ":help" are 'commands'
                    if handle_cmd(line[1:]) == 1:
                        break
                else:
                    # Treat this as an utterance
                    history.append(line)
                    chat.append(line)
                    ws.emit(
                        Message("recognizer_loop:utterance", {
                            'utterances': [line.strip()],
                            'lang': 'en-us'
                        }))
                hist_idx = -1
                line = ""
            elif c == 16 or c == 545:  # Ctrl+P or Ctrl+Left (Previous)
                # Move up the history stack
                hist_idx = clamp(hist_idx + 1, -1, len(history) - 1)
                if hist_idx >= 0:
                    line = history[len(history) - hist_idx - 1]
                else:
                    line = ""
            elif c == 14 or c == 560:  # Ctrl+N or Ctrl+Right (Next)
                # Move down the history stack
                hist_idx = clamp(hist_idx - 1, -1, len(history) - 1)
                if hist_idx >= 0:
                    line = history[len(history) - hist_idx - 1]
                else:
                    line = ""
            elif c == curses.KEY_LEFT:
                # scroll long log lines left
                log_line_lr_scroll += curses.COLS // 4
            elif c == curses.KEY_RIGHT:
                # scroll long log lines right
                log_line_lr_scroll -= curses.COLS // 4
                if log_line_lr_scroll < 0:
                    log_line_lr_scroll = 0
            elif c == curses.KEY_HOME:
                # HOME scrolls log lines all the way to the start
                log_line_lr_scroll = longest_visible_line
            elif c == curses.KEY_END:
                # END scrolls log lines all the way to the end
                log_line_lr_scroll = 0
            elif c == curses.KEY_UP:
                scroll_log(False, 1)
            elif c == curses.KEY_DOWN:
                scroll_log(True, 1)
            elif c == curses.KEY_NPAGE:  # aka PgDn
                # PgDn to go down a page in the logs
                scroll_log(True)
            elif c == curses.KEY_PPAGE:  # aka PgUp
                # PgUp to go up a page in the logs
                scroll_log(False)
            elif c == curses.KEY_RESIZE:
                # Generated by Curses when window/screen has been resized
                y, x = scr.getmaxyx()
                curses.resizeterm(y, x)

                # resizeterm() causes another curses.KEY_RESIZE, so
                # we need to capture that to prevent a loop of resizes
                c = scr.getch()
            elif c == curses.KEY_BACKSPACE or c == 127:
                # Backspace to erase a character in the utterance
                line = line[:-1]
            elif c == 6:  # Ctrl+F (Find)
                line = ":find "
            elif c == 24:  # Ctrl+X (Exit)
                if find_str:
                    # End the find session
                    find_str = None
                    rebuild_filtered_log()
            elif curses.ascii.isascii(c):
                # Accept typed character in the utterance
                line += chr(c)

            # DEBUG: Uncomment the following code to see what key codes
            #        are generated when an unknown key is pressed.
            # else:
            #    line += str(c)

    except KeyboardInterrupt as e:
        # User hit Ctrl+C to quit
        pass
    except KeyboardInterrupt as e:
        LOG.exception(e)
    finally:
        scr.erase()
        scr.refresh()
        scr = None
        pass
Esempio n. 54
0
class Enclosure:
    """
    Serves as a communication interface between Arduino and Mycroft Core.

    ``Enclosure`` initializes and aggregates all enclosures implementation.

    E.g. ``EnclosureEyes``, ``EnclosureMouth`` and ``EnclosureArduino``

    It also listens to the basis events in order to perform those core actions
    on the unit.

    E.g. Start and Stop talk animation
    """

    def __init__(self):
        self.__init_serial()
        self.client = WebsocketClient()
        self.reader = EnclosureReader(self.serial, self.client)
        self.writer = EnclosureWriter(self.serial, self.client)
        self.eyes = EnclosureEyes(self.client, self.writer)
        self.mouth = EnclosureMouth(self.client, self.writer)
        self.system = EnclosureArduino(self.client, self.writer)
        self.weather = EnclosureWeather(self.client, self.writer)
        self.__register_events()

    def setup(self):
        must_upload = self.config.get('must_upload')
        if must_upload is not None and str2bool(must_upload):
            ConfigurationManager.set('enclosure', 'must_upload', False)
            time.sleep(5)
            self.client.emit(Message("speak", metadata={
                'utterance': "I am currently uploading to the arduino."}))
            self.client.emit(Message("speak", metadata={
                'utterance': "I will be finished in just a moment."}))
            self.upload_hex()
            self.client.emit(Message("speak", metadata={
                'utterance': "Arduino programing complete."}))

        must_start_test = self.config.get('must_start_test')
        if must_start_test is not None and str2bool(must_start_test):
            ConfigurationManager.set('enclosure', 'must_start_test', False)
            time.sleep(0.5)  # Ensure arduino has booted
            self.client.emit(Message("speak", metadata={
                'utterance': "Begining hardware self test."}))
            self.writer.write("test.begin")

    @staticmethod
    def upload_hex():
        old_path = os.getcwd()
        try:
            os.chdir('/opt/enclosure/')
            subprocess.check_call('./upload.sh')
        finally:
            os.chdir(old_path)

    def __init_serial(self):
        try:
            self.config = ConfigurationManager.get().get("enclosure")
            self.port = self.config.get("port")
            self.rate = int(self.config.get("rate"))
            self.timeout = int(self.config.get("timeout"))
            self.serial = serial.serial_for_url(
                url=self.port, baudrate=self.rate, timeout=self.timeout)
            LOGGER.info(
                "Connected to: " + self.port + " rate: " + str(self.rate) +
                " timeout: " + str(self.timeout))
        except:
            LOGGER.error(
                "It is not possible to connect to serial port: " + self.port)
            raise

    def __register_events(self):
        self.client.on('mycroft.paired', self.__update_events)
        self.client.on('enclosure.mouth.listeners', self.__mouth_listeners)
        self.__register_mouth_events()

    def __mouth_listeners(self, event=None):
        if event and event.metadata:
            active = event.metadata['active']
            if active:
                self.__register_mouth_events()
            else:
                self.__remove_mouth_events()

    def __register_mouth_events(self):
        self.client.on('recognizer_loop:record_begin', self.mouth.listen)
        self.client.on('recognizer_loop:record_end', self.mouth.reset)
        self.client.on('recognizer_loop:audio_output_start', self.mouth.talk)
        self.client.on('recognizer_loop:audio_output_end', self.mouth.reset)

    def __remove_mouth_events(self):
        self.client.remove('recognizer_loop:record_begin', self.mouth.listen)
        self.client.remove('recognizer_loop:record_end', self.mouth.reset)
        self.client.remove('recognizer_loop:audio_output_start',
                           self.mouth.talk)
        self.client.remove('recognizer_loop:audio_output_end',
                           self.mouth.reset)

    def __update_events(self, event=None):
        if event and event.metadata:
            if event.metadata.get('paired', False):
                self.__register_mouth_events()
            else:
                self.__remove_mouth_events()

    def run(self):
        try:
            self.client.run_forever()
        except Exception as e:
            LOGGER.error("Client error: {0}".format(e))
            self.stop()

    def stop(self):
        self.writer.stop()
        self.reader.stop()
        self.serial.close()
Esempio n. 55
0
def gui_main(stdscr):
    global scr
    global ws
    global line
    global log_line_lr_scroll
    global longest_visible_line
    global find_str
    global last_key

    scr = stdscr
    init_screen()

    ws = WebsocketClient()
    ws.on('speak', handle_speak)
    ws.on('message', handle_message)
    event_thread = Thread(target=connect)
    event_thread.setDaemon(True)
    event_thread.start()

    history = []
    hist_idx = -1  # index, from the bottom
    try:
        input = ""
        while True:
            draw_screen()

            c = scr.getch()

            # Convert VT100 ESC codes generated by some terminals
            if c == 27:
                c1 = scr.getch()
                c2 = scr.getch()
                if c1 == 79 and c2 == 120:
                    c = curses.KEY_UP
                elif c1 == 79 and c2 == 116:
                    c = curses.KEY_LEFT
                elif c1 == 79 and c2 == 114:
                    c = curses.KEY_DOWN
                elif c1 == 79 and c2 == 118:
                    c = curses.KEY_RIGHT
                elif c1 == 79 and c2 == 121:
                    c = curses.KEY_PPAGE  # aka PgUp
                elif c1 == 79 and c2 == 115:
                    c = curses.KEY_NPAGE  # aka PgDn
                elif c1 == 79 and c2 == 119:
                    c = curses.KEY_HOME
                elif c1 == 79 and c2 == 113:
                    c = curses.KEY_END
                else:
                    c = c2
                last_key = str(c)+",ESC+"+str(c1)+"+"+str(c2)
            else:
                last_key = str(c)

            if c == curses.KEY_ENTER or c == 10 or c == 13:
                # ENTER sends the typed line to be processed by Mycroft
                if line == "":
                    continue

                if line[:1] == ":":
                    # Lines typed like ":help" are 'commands'
                    if handle_cmd(line[1:]) == 1:
                        break
                else:
                    # Treat this as an utterance
                    history.append(line)
                    chat.append(line)
                    ws.emit(Message("recognizer_loop:utterance",
                                    {'utterances': [line.strip()],
                                     'lang': 'en-us'}))
                hist_idx = -1
                line = ""
            elif c == 16 or c == 545:  # Ctrl+P or Ctrl+Left (Previous)
                # Move up the history stack
                hist_idx = clamp(hist_idx + 1, -1, len(history) - 1)
                if hist_idx >= 0:
                    line = history[len(history) - hist_idx - 1]
                else:
                    line = ""
            elif c == 14 or c == 560:  # Ctrl+N or Ctrl+Right (Next)
                # Move down the history stack
                hist_idx = clamp(hist_idx - 1, -1, len(history) - 1)
                if hist_idx >= 0:
                    line = history[len(history) - hist_idx - 1]
                else:
                    line = ""
            elif c == curses.KEY_LEFT:
                # scroll long log lines left
                log_line_lr_scroll += curses.COLS // 4
            elif c == curses.KEY_RIGHT:
                # scroll long log lines right
                log_line_lr_scroll -= curses.COLS // 4
                if log_line_lr_scroll < 0:
                    log_line_lr_scroll = 0
            elif c == curses.KEY_HOME:
                # HOME scrolls log lines all the way to the start
                log_line_lr_scroll = longest_visible_line
            elif c == curses.KEY_END:
                # END scrolls log lines all the way to the end
                log_line_lr_scroll = 0
            elif c == curses.KEY_UP:
                scroll_log(False, 1)
            elif c == curses.KEY_DOWN:
                scroll_log(True, 1)
            elif c == curses.KEY_NPAGE:  # aka PgDn
                # PgDn to go down a page in the logs
                scroll_log(True)
            elif c == curses.KEY_PPAGE:  # aka PgUp
                # PgUp to go up a page in the logs
                scroll_log(False)
            elif c == 2 or c == 550:  # Ctrl+B or Ctrl+PgDn
                scroll_log(True, max_log_lines)
            elif c == 20 or c == 555:  # Ctrl+T or Ctrl+PgUp
                scroll_log(False, max_log_lines)
            elif c == curses.KEY_RESIZE:
                # Generated by Curses when window/screen has been resized
                y, x = scr.getmaxyx()
                curses.resizeterm(y, x)

                # resizeterm() causes another curses.KEY_RESIZE, so
                # we need to capture that to prevent a loop of resizes
                c = scr.getch()
            elif c == curses.KEY_BACKSPACE or c == 127:
                # Backspace to erase a character in the utterance
                line = line[:-1]
            elif c == 6:  # Ctrl+F (Find)
                line = ":find "
            elif c == 24:  # Ctrl+X (Exit)
                if find_str:
                    # End the find session
                    find_str = None
                    rebuild_filtered_log()
            elif curses.ascii.isascii(c):
                # Accept typed character in the utterance
                line += chr(c)

            # DEBUG: Uncomment the following code to see what key codes
            #        are generated when an unknown key is pressed.
            # else:
            #    line += str(c)

    except KeyboardInterrupt as e:
        # User hit Ctrl+C to quit
        pass
    except KeyboardInterrupt as e:
        LOG.exception(e)
    finally:
        scr.erase()
        scr.refresh()
        scr = None
        pass