def load_objects(self, file_name):
         # load an object
         try:
             with open (file_name) as json_file:
                 json_data = json.load(json_file)
             print(json_data)
              # build message
             msg = OpalCommand()
             # add header
             msg.header = Header()
             msg.header.stamp = rospy.Time.now()
             msg.command = OpalCommand.LOAD_OBJECT
             # add the object properties to the message 
             # (the loaded json data)
             msg.properties = json.dumps(json_data) 
             # send Opal message to tablet game
             self.pub.publish(msg)
             rospy.loginfo(msg)
             self.r.sleep()
         except ValueError as e:
             print('Error! Could not open or parse json config file!'
                 + '\n  Did you put only one game object config in'
                 + ' the file?\n  Did you use valid json?'
                 + '\nError: %s' % e)
         except IOError as e:
             print('Error! Could not open or could not parse json '
                    +'config file!'
                 + '\n  Does the file exist in this directory, or did'
                 + ' you specify the full file path?'
                 + '\n  Did you include the file extension, if there is'
                 + ' one?\nError: %s' % e)
Esempio n. 2
0
 def send_opal_command(self, command, properties=None):
     """ Publish opal command message. Optionally, wait for a response. """
     if self._opal_pub is None:
         self._logger.warning("OpalCommand ROS publisher is none!")
         return
     self._logger.info("Sending opal command: " + command)
     # Build message.
     msg = OpalCommand()
     # Add header.
     msg.header = Header()
     msg.header.stamp = rospy.Time.now()
     # We keep a dictionary of the strings used in the script and the actual
     # OpalCommand constants to use for lookup. If we don't find the command
     # given to us in our dictionary, we won't send it. We do, however,
     # print a warning to the user so they can check whether their list of
     # possible commands to send is up-to-date or whether they spelled
     # soemthing wrong.
     try:
         msg.command = self.OPAL_COMMANDS[command]
     except KeyError:
         self._logger.warning("Not sending invalid OpalCommand: ", command)
         return
     # Some commands require properties. If the command is one that requires
     # properties, we shouldn't send the message if we didn't get any
     # properties. If we got properties but the command doesn't need them,
     # we won't add them to the message.
     if (  # Properties: a string with the name of action to do.
             "SIDEKICK_DO" in command
             # Properties: a string with the name of audio file to play.
             or "SIDEKICK_SAY" in command
             # Properties: JSON defining what object to load.
             or "LOAD_OBJECT" in command
             # Properties: JSON defining what object to move where.
             or "MOVE_OBJECT" in command
             # Properties: JSON listing names of objects that are correct or
             # incorrect.
             or "SET_CORRECT" in command
             # Properties: a string with name of the object to highlight.
             or "HIGHLIGHT" in command
             # Properties: JSON listing scene attributes.
             or "SETUP_STORY_SCENE" in command
             # Properties: string name of the story to load next.
             or "STORY_SELECTION" in command
             # Properties: int number of the page to go to.
             or "STORY_GO_TO_PAGE" in command):
         # Add properties if we got them. We assume any properties
         # provided are in the correct format for the command.
         if properties:
             msg.properties = properties
         else:
             self._logger.warning(
                 "Did not get properties for OpalCommand "
                 "{}! Not sending empty command.".format(command))
             return
     # If we have properties for a command that needs them, or no properties
     # for commands that don't, send the message.
     self._opal_pub.publish(msg)
     self._logger.debug(msg)
 def send_opal_message(self, command):
     """ Publish opal command message """
     print 'sending opal command: %s' % command
     msg = OpalCommand()
     # add header
     msg.header = Header()
     msg.header.stamp = rospy.Time.now()
     msg.command = command
     self.tablet_pub.publish(msg)
     rospy.loginfo(msg)
Esempio n. 4
0
 def send_opal_message(self, command):
     """ Publish opal command message """
     if self.tablet_pub is not None:
         print('sending opal command: %s' % command)
         msg = OpalCommand()
         # add header
         msg.header = Header()
         msg.header.stamp = rospy.Time.now()
         msg.command = command
         self.tablet_pub.publish(msg)
         rospy.loginfo(msg)
def opal_sender():
    # parse python arguments 
    parser = argparse.ArgumentParser(
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description='Send a message to a' 
            + ' SAR Opal project tablet. Must have roscore and '
            + 'rosbridge_server running for message to be sent.')
    parser.add_argument('-l', '--load', dest='loadme', action='append', nargs='+',
            help='load the game object specified in this json config file' +
            ' on the tablet')
    parser.add_argument('-t', '--touch', choices=['enable','e','disable','d'],
            type=str, dest='touch',help='enable/disable touch events on tablet')
    parser.add_argument('-r', '--reset', action='store_true',
            help='reload all objects and reset scene on tablet')
    parser.add_argument('-d', '--sidekick_do', dest='sidekick_do', 
            action='append', nargs='+', type=str,
            help='tells sidekick to do specified action')
    parser.add_argument('-s', '--sidekick_say', dest='sidekick_say', 
            action='append', nargs='+', type=str,
            help='tells sidekick to say specified speech')
    parser.add_argument('-c', '--clear', dest='clear_me', action='append',
            nargs='?', type=str, default=None,
            help='clear objects from tablet screen')
    parser.add_argument('-m', '--move', dest='moveme', action='append',
            nargs='+', help='move the game object specified in this json'
            +' config file to the specified position on the tablet')
    parser.add_argument('-i', '--highlight', dest='highlight',
            action='append', nargs='+', type=str, help='highlight '
            + 'the specified game object')
    parser.add_argument('-k', '--keyframe', action='store_true',
            help='request the state of all objects on the tablet')
    parser.add_argument('-f', '--fade', choices=['fade','f','unfade','u'],
            type=str, dest='fade', help='fade/unfade screen on tablet')
    parser.add_argument('-q', '--quit', action='store_true', 
            help='quit the tablet app')
    parser.add_argument('-e', '--set_correct', dest='set_correct',
            action='append', nargs='+', help='tag game objects as correct' +
            ' or as incorrect')
    parser.add_argument('-w', '--correct', choices=['show','s','hide','h'],
            type=str, dest='correct', help='show/hide visual feedback ' +
            'for correct/incorrect game objects')
    parser.add_argument('-u', '--setup_scene', dest='setup_scene',
            action='append', nargs='+', help='set up initial game scene for'
            + ' a social stories game')
    
    args = parser.parse_args()
    print(args)
    
    # now build a message based on the command:
    # open ros up here, then run through the below and send all

    # start ROS node
    pub = rospy.Publisher('opal_tablet_command', OpalCommand, queue_size=10)
    rospy.init_node('opal_sender', anonymous=True)
    r = rospy.Rate(10) # spin at 10 Hz
    r.sleep() # sleep to wait for subscribers

    # start building message
    msg = OpalCommand()
    # add header
    msg.header = Header()
    msg.header.stamp = rospy.Time.now()

    # fill in command and properties:

    # load an object
    if args.loadme:
        # for each object to load, send a message
        for obj in args.loadme:
            # parse config file to get details of object or
            # background to load
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                 # build message
                msg.command = OpalCommand.LOAD_OBJECT
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n  Did you put only one game object config in'
                    + ' the file?\n  Did you use valid json?'
                    + '\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # sidekick do an action
    if args.sidekick_do:
        # build message
        msg.command = OpalCommand.SIDEKICK_DO
        msg.properties = args.sidekick_do[0]

    # sidekick say something
    if args.sidekick_say:
        # build message
        msg.command = OpalCommand.SIDEKICK_SAY
        msg.properties = args.sidekick_say[0]

    # send enable or disable touch events command
    if args.touch:
        # build message
        msg.command = OpalCommand.ENABLE_TOUCH if args.touch == 'enabled' \
                or args.touch == 'e' else OpalCommand.DISABLE_TOUCH

    # send reset scene and reload objects command
    if args.reset:
        print('reload');
        # build message
        msg.command = OpalCommand.RESET

    # send clear scene command
    if args.clear_me:
        print('clear');
        # build message
        msg.command = OpalCommand.CLEAR
        if args.clear_me[0]:
            msg.properties = args.clear_me[0]
    
    # send quit command
    if args.quit:
        print('quit');
        # build message
        msg.command = OpalCommand.EXIT


    # send move object command
    # for each object to move, send a message
    if args.moveme:
        for obj in args.moveme:
            # parse config file to get details of object or
            # background to load
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                 # build message
                msg.command = OpalCommand.MOVE_OBJECT
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n  Did you put only one game object config in'
                    + ' the file?\n  Did you use valid json?'
                    + '\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # send highlight object command
    if args.highlight:
        # build message
        msg.command = OpalCommand.HIGHLIGHT_OBJECT
        msg.properties = args.highlight[0]

    # send request keyframe command
    if args.keyframe:
        print('request keyframe');
        # build message
        msg.command = OpalCommand.REQUEST_KEYFRAME

    # send fade or unfade screen command
    if args.fade:
        # build message
        msg.command = OpalCommand.FADE_SCREEN if args.touch == 'fade' \
                or args.touch == 'f' else OpalCommand.UNFADE_SCREEN

    # send set correct command 
    if args.set_correct:
        for obj in args.set_correct:
            # parse config file to get details of object or
            # background to load
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                # build message
                msg.command = OpalCommand.SET_CORRECT
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n Did you use valid json?\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # send show correct or hide correct command
    if args.correct:
        # build message
        msg.command = OpalCommand.SHOW_CORRECT if args.correct == 'show' \
                or args.correct == 's' else OpalCommand.HIDE_CORRECT

    # send setup social story scene message 
    if args.setup_scene:
        # for each scene to setup, send a message
        # it would be weird to do setup more than once, since the scene
        # clears before setup (so only the last setup would really count)
        for obj in args.setup_scene:
            # parse config file to get details of scene 
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                 # build message
                msg.command = OpalCommand.SETUP_STORY_SCENE
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n  Did you put only one scene setup config in'
                    + ' the file?\n  Did you use valid json?'
                    + '\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # send Opal message to tablet game
    pub.publish(msg)
    rospy.loginfo(msg)
    r.sleep()
def opal_sender():
    # parse python arguments 
    parser = argparse.ArgumentParser(
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description='Send a message to a' 
            + ' SAR Opal project tablet. Must have roscore and '
            + 'rosbridge_server running for message to be sent.')
    parser.add_argument('-l', '--load', dest='loadme', action='append', nargs='?',
            help='load the game object specified in this json config file' +
            ' on the tablet')
    parser.add_argument('-t', '--touch', choices=['enable','e','disable','d'],
            type=str, dest='touch',help='enable/disable touch events on tablet')
    parser.add_argument('-r', '--reset', action='store_true',
            help='reload all objects and reset scene on tablet')
    parser.add_argument('-d', '--sidekick_do', dest='sidekick_do', 
            action='append', nargs='?', type=str,
            help='tells sidekick to do specified action')
    parser.add_argument('-s', '--sidekick_say', dest='sidekick_say', 
            action='append', nargs='?', type=str,
            help='tells sidekick to say specified speech')
    parser.add_argument('-c', '--clear', action='store_true',
            help='clear all objects from tablet screen')
    parser.add_argument('-m', '--move', dest='moveme', action='append',
            nargs='?', help='move the game object specified in this json'
            +' config file to the specified position on the tablet')
    parser.add_argument('-i', '--highlight', dest='highlight',
            action='append', nargs='?', type=str, help='highlight '
            + 'the specified game object')
    parser.add_argument('-k', '--keyframe', action='store_true',
            help='request the state of all objects on the tablet')
    parser.add_argument('-f', '--fade', choices=['fade','f','unfade','u'],
            type=str, dest='fade', help='fade/unfade screen on tablet')
    parser.add_argument('-q', '--quit', action='store_true', 
            help='quit the tablet app')
    parser.add_argument('-e', '--set_correct', dest='set_correct',
            action='append', nargs='?', help='tag game objects as correct' +
            ' or as incorrect')
    parser.add_argument('-w', '--correct', choices=['show','s','hide','h'],
            type=str, dest='correct', help='show/hide visual feedback ' +
            'for correct/incorrect game objects')
    parser.add_argument('-u', '--setup_scene', dest='setup_scene',
            action='append', nargs='?', help='set up initial game scene for'
            + ' a social stories game')
    
    args = parser.parse_args()
    print(args)
    
    # now build a message based on the command:
    # open ros up here, then run through the below and send all

    # start ROS node
    pub = rospy.Publisher('opal_tablet_command', OpalCommand, queue_size=10)
    rospy.init_node('opal_sender', anonymous=True)
    r = rospy.Rate(10) # spin at 10 Hz
    r.sleep() # sleep to wait for subscribers


    # load an object
    if args.loadme:
        # for each object to load, send a message
        for obj in args.loadme:
            # parse config file to get details of object or
            # background to load
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                 # build message
                msg = OpalCommand()
                # add header
                msg.header = Header()
                msg.header.stamp = rospy.Time.now()
                msg.command = OpalCommand.LOAD_OBJECT
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
                # send Opal message to tablet game
                pub.publish(msg)
                rospy.loginfo(msg)
                r.sleep()
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n  Did you put only one game object config in'
                    + ' the file?\n  Did you use valid json?'
                    + '\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # sidekick do an action
    if args.sidekick_do:
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.SIDEKICK_DO
        msg.properties = args.sidekick_do[0]
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # sidekick say something
    if args.sidekick_say:
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.SIDEKICK_SAY
        msg.properties = args.sidekick_say[0]
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send enable or disable touch events command
    if args.touch:
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.ENABLE_TOUCH if args.touch == 'enabled' or args.touch == 'e' else OpalCommand.DISABLE_TOUCH
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send reset scene and reload objects command
    if args.reset:
        print('reload');
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.RESET
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send clear scene command
    if args.clear:
        print('clear');
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.CLEAR
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()
    
    # send quit command
    if args.quit:
        print('quit');
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.EXIT
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()


    # send move object command
    # for each object to move, send a message
    if args.moveme:
        for obj in args.moveme:
            # parse config file to get details of object or
            # background to load
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                 # build message
                msg = OpalCommand()
                # add header
                msg.header = Header()
                msg.header.stamp = rospy.Time.now()
                msg.command = OpalCommand.LOAD_OBJECT
                msg.command = OpalCommand.MOVE_OBJECT
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
                # send Opal message to tablet game
                pub.publish(msg)
                rospy.loginfo(msg)
                r.sleep()
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n  Did you put only one game object config in'
                    + ' the file?\n  Did you use valid json?'
                    + '\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # send highlight object command
    if args.highlight:
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.HIGHLIGHT_OBJECT
        msg.properties = args.highlight[0]
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send request keyframe command
    if args.keyframe:
        print('request keyframe');
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.REQUEST_KEYFRAME
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send fade or unfade screen command
    if args.fade:
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.FADE_SCREEN if args.touch == 'fade' or args.touch == 'f' else OpalCommand.UNFADE_SCREEN
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send set correct command 
    if args.set_correct:
        for obj in args.set_correct:
            # parse config file to get details of object or
            # background to load
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                # build message
                msg = OpalCommand()
                # add header
                msg.header = Header()
                msg.header.stamp = rospy.Time.now()
                msg.command = OpalCommand.LOAD_OBJECT
                msg.command = OpalCommand.SET_CORRECT
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
                # send Opal message to tablet game
                pub.publish(msg)
                rospy.loginfo(msg)
                r.sleep()
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n Did you use valid json?\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)

    # send show correct or hide correct command
    if args.correct:
        # build message
        msg = OpalCommand()
        # add header
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        msg.command = OpalCommand.LOAD_OBJECT
        msg.command = OpalCommand.SHOW_CORRECT if args.correct == 'show' or args.correct == 's' else OpalCommand.HIDE_CORRECT
        # send Opal message to tablet game
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

    # send setup social story scene message 
    if args.setup_scene:
        # for each scene to setup, send a message
        # it would be weird to do setup more than once, since the scene
        # clears before setup (so only the last setup would really count)
        for obj in args.setup_scene:
            # parse config file to get details of scene 
            try:
                with open (obj) as json_file:
                    json_data = json.load(json_file)
                print(json_data)
                 # build message
                msg = OpalCommand()
                # add header
                msg.header = Header()
                msg.header.stamp = rospy.Time.now()
                msg.command = OpalCommand.LOAD_OBJECT
                msg.command = OpalCommand.SETUP_STORY_SCENE
                # add the object properties to the message 
                # (the loaded json data)
                msg.properties = json.dumps(json_data) 
                # send Opal message to tablet game
                pub.publish(msg)
                rospy.loginfo(msg)
                r.sleep()
            except ValueError as e:
                print('Error! Could not open or parse json config file!'
                    + '\n  Did you put only one scene setup config in'
                    + ' the file?\n  Did you use valid json?'
                    + '\nError: %s' % e)
            except IOError as e:
                print('Error! Could not open or could not parse json '
                       +'config file!'
                    + '\n  Does the file exist in this directory, or did'
                    + ' you specify the full file path?'
                    + '\n  Did you include the file extension, if there is'
                    + ' one?\nError: %s' % e)
Esempio n. 7
0
    def send_opal_command(self, command, properties=None, response=None,
            timeout=None):
        """ Publish opal command message. Optionally, wait for a
        response.
        """
        self._logger.info("Sending opal command: " + command)
        # Build message.
        msg = OpalCommand()
        # Add header.
        msg.header = Header()
        msg.header.stamp = rospy.Time.now()
        # Add appropriate command and properties if there are any.
        # We check properties for each command individually, since some
        # require properties, and if there are none, we shouldn't send
        # the message. We assume any properties provided are in the
        # correct format for the command.
        if "RESET" in command:
            msg.command = OpalCommand.RESET
        elif "DISABLE_TOUCH" in command:
            msg.command = OpalCommand.DISABLE_TOUCH
        elif "ENABLE_TOUCH" in command:
            msg.command = OpalCommand.ENABLE_TOUCH
        elif "SIDEKICK_DO" in command:
            msg.command = OpalCommand.SIDEKICK_DO
            # Properties: a string with the name of action to do.
        elif "SIDEKICK_SAY" in command:
            msg.command = OpalCommand.SIDEKICK_SAY
            # Properties: a string with the name of audio file to play.
            if properties:
                msg.properties = properties
            else:
                self._logger.warning("Did not get properties for a "
                    + "SIDEKICK_SAY command! Not sending empty command.")
                return
        elif "LOAD_OBJECT" in command:
            msg.command = OpalCommand.LOAD_OBJECT
            # Properties: JSON defining what object to load.
            if properties:
                msg.properties = properties
            else:
                self._logger.warning("Did not get properties for a "
                    + "LOAD_OBJECT command! Not sending empty command.")
                return
        elif "CLEAR" in command:
            msg.command = OpalCommand.CLEAR
            # Properties: optionally, string defining what objects to
            # remove.
            if properties:
                msg.properties = properties
        elif "MOVE_OBJECT" in command:
            msg.command = OpalCommand.MOVE_OBJECT
            # Properties: JSON defining what object to move where.
            if properties:
                msg.properties = properties
            else:
                self._logger.warning("Did not get properties for a "
                    + "MOVE_OBJECT command! Not sending empty command.")
                return
        elif "HIGHLIGHT" in command:
            msg.command = OpalCommand.HIGHLIGHT_OBJECT
            # Properties: a string with name of the object to highlight.
            if properties:
                msg.properties = properties
            else:
                self._logger.warning("Did not get properties for a "
                    + "HIGHLIGHT_OBJECT command! Adding null properties.")
        elif "REQUEST_KEYFRAME" in command:
            msg.command = OpalCommand.REQUEST_KEYFRAME
        elif "FADE_SCREEN" in command:
            msg.command = OpalCommand.FADE_SCREEN
        elif "UNFADE_SCREEN" in command:
            msg.command = OpalCommand.UNFADE_SCREEN
        elif "NEXT_PAGE" in command:
            msg.command = OpalCommand.NEXT_PAGE
        elif "PREV_PAGE" in command:
            msg.command = OpalCommand.PREV_PAGE
        elif "EXIT" in command:
            msg.command = OpalCommand.EXIT
        elif "SET_CORRECT" in command:
            msg.command = OpalCommand.SET_CORRECT
            # Properties: JSON listing names of objects that are
            # correct or incorrect.
            if properties:
                msg.properties = properties
            else:
                self._logger.warning("Did not get properties for a "
                    + "SET_CORRECT command! Not sending empty command.")
                return
        elif "SHOW_CORRECT" in command:
            msg.command = OpalCommand.SHOW_CORRECT
        elif "HIDE_CORRECT" in command:
            msg.command = OpalCommand.HIDE_CORRECT
        elif "SETUP_STORY_SCENE" in command:
            msg.command = OpalCommand.SETUP_STORY_SCENE
            # Properties: JSON listing scene attributes.
            if properties:
                msg.properties = properties
            else:
                self._logger.warning("Did not get properties for a "
                    + "SETUP_STORY_SCENE command! Not sending empty command.")
                return
        else:
            self._logger.warning("Not sending invalid OpalCommand: ", command)
            return
        # Send message.
        self._game_pub.publish(msg)
        self._logger.debug(msg)

        # If we got a response to wait for and a timeout value, wait
        # for a response.
        if response and timeout:
            self.wait_for_response(response, timeout)