Example #1
0
    def device_class_init(cls, machine: MachineController):
        """Initialise lights.

        Args:
            machine: MachineController object
        """
        cls.machine = machine
        cls.lights_to_fade = set()
        cls.lights_to_update = set()

        machine.validate_machine_config_section('matrix_light_settings')

        cls._updater_task = machine.clock.schedule_interval(
            cls.update_matrix_lights,
            1 / machine.config['mpf']['default_matrix_light_hw_update_hz'])

        machine.mode_controller.register_stop_method(cls.mode_stop)

        machine.settings.add_setting(
            SettingEntry("brightness", "Brightness", 100, "brightness", 1.0, {
                0.25: "25%",
                0.5: "50%",
                0.75: "75%",
                1.0: "100% (default)"
            }))
Example #2
0
class Command(object):
    """Performs hardware operations."""
    def __init__(self, mpf_path, machine_path, args):
        """Parse args."""
        self.mpf_path = mpf_path
        self.machine_path = machine_path
        self.args = args
        self.mpf = MachineController(
            self.mpf_path, self.machine_path, {
                "bcp": False,
                "no_load_cache": False,
                "mpfconfigfile": os.path.join(mpf_path, "mpfconfig.yaml"),
                "configfile": ["config"],
                "create_config_cache": False,
                "force_platform": False,
                "text_ui": False
            })
        self.mpf.initialise_mpf()

    def scan(self):
        """Scan hardware."""
        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.get_info_string())
            print("---------")
Example #3
0
    def __init__(self, args, path):
        """Parse args."""
        command_name = args.pop(1)
        super().__init__(args=args, path=path)

        machine_path, remaining_args = self.parse_args()
        self.machine_path = machine_path
        self.args = remaining_args
        config_loader = YamlMultifileConfigLoader(machine_path,
                                                  ["config.yaml"], True, False)

        config = config_loader.load_mpf_config()

        self.mpf = MachineController(
            {
                "bcp": False,
                "no_load_cache": False,
                "mpfconfigfile": os.path.join(self.mpf_path, "mpfconfig.yaml"),
                "configfile": ["config"],
                "production": False,
                "create_config_cache": False,
                "force_platform": False,
                "text_ui": False
            }, config)
        self.mpf.clock.loop.run_until_complete(
            self.mpf.initialise_core_and_hardware())
        if self.mpf.thread_stopper.is_set():
            raise AssertionError("Initialisation failed!")

        method = getattr(self, command_name)
        method()
Example #4
0
    def __init__(self, args, path):
        """Parse args."""
        command_name = args.pop(1)
        super().__init__(args=args, path=path)

        machine_path, remaining_args = self.parse_args()
        self.machine_path = machine_path
        self.args = remaining_args
        config_loader = YamlMultifileConfigLoader(machine_path,
                                                  ["config.yaml"], True, False)

        config = config_loader.load_mpf_config()

        self.mpf = MachineController(
            {
                "bcp": False,
                "no_load_cache": False,
                "mpfconfigfile": os.path.join(self.mpf_path, "mpfconfig.yaml"),
                "configfile": ["config"],
                "production": False,
                "create_config_cache": False,
                "force_platform": False,
                "text_ui": False
            }, config)

        method = getattr(self, command_name)
        method()
Example #5
0
class Command(MpfCommandLineParser):
    """Performs hardware operations."""
    def __init__(self, args, path):
        """Parse args."""
        command_name = args.pop(1)
        super().__init__(args=args, path=path)

        machine_path, remaining_args = self.parse_args()
        self.machine_path = machine_path
        self.args = remaining_args
        config_loader = YamlMultifileConfigLoader(machine_path,
                                                  ["config.yaml"], True, False)

        config = config_loader.load_mpf_config()

        self.mpf = MachineController(
            {
                "bcp": False,
                "no_load_cache": False,
                "mpfconfigfile": os.path.join(self.mpf_path, "mpfconfig.yaml"),
                "configfile": ["config"],
                "production": False,
                "create_config_cache": False,
                "force_platform": False,
                "text_ui": False
            }, config)
        self.mpf.clock.loop.run_until_complete(
            self.mpf.initialise_core_and_hardware())
        if self.mpf.thread_stopper.is_set():
            raise AssertionError("Initialisation failed!")

        method = getattr(self, command_name)
        method()

    def scan(self):
        """Scan hardware."""
        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.get_info_string())
            print("---------")

        self.mpf.shutdown()

    def firmware_update(self):
        """Upgrade firmware of platforms."""
        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.update_firmware())
            print("---------")

        self.mpf.shutdown()
Example #6
0
class Command:

    """Runs the mpf game."""

    # pylint: disable-msg=too-many-locals,too-many-statements
    def __init__(self, mpf_path, machine_path, args):
        """Generate wiring for game from MPL file."""
        del mpf_path
        self.machine = None
        self._sigint_count = 0

        parser = argparse.ArgumentParser(description='Generates wiring .yaml file')

        parser.add_argument("-c",
                            action="store", dest="configfile",
                            default="config.yaml", metavar='config_file',
                            help="The name of a config file to load. Default "
                                 "is "
                                 "config.yaml. Multiple files can be used "
                                 "via a comma-"
                                 "separated list (no spaces between)")

        self.args = parser.parse_args(args)
        self.args.configfile = Util.string_to_event_list(self.args.configfile)

        # To initialize and check machine, load it onto the virtual platform - we have to use the virtual platform
        # because it would be helpful to be able to calculate wiring before setting up physical hardware.
        self.args.__dict__["production"] = False
        self.args.__dict__["force_platform"] = "smart_virtual"
        self.args.__dict__["text_ui"] = False
        self.args.__dict__["bcp"] = False

        config_loader = YamlMultifileConfigLoader(machine_path, self.args.configfile,
                                                  False, False)

        config = config_loader.load_mpf_config()

        # print(config.get_machine_config())

        self.machine = MachineController(vars(self.args), config)
        self.machine.initialise_mpf()

        result = wire(self.machine)

        yaml = YAML()
        yaml.default_flow_style = False
        f = open("wiring.yaml", "w", encoding="utf-8")
        yaml.dump(result, f)
        f.close()
Example #7
0
 def __init__(self, mpf_path, machine_path, args):
     """Parse args."""
     self.mpf_path = mpf_path
     self.machine_path = machine_path
     self.args = args
     self.mpf = MachineController(
         self.mpf_path, self.machine_path, {
             "bcp": False,
             "no_load_cache": False,
             "mpfconfigfile": os.path.join(mpf_path, "mpfconfig.yaml"),
             "configfile": ["config"],
             "create_config_cache": False,
             "force_platform": False,
             "text_ui": False
         })
     self.mpf.initialise_mpf()
Example #8
0
 def __init__(self, mpf_path, machine_path, args):
     """Parse args."""
     self.mpf_path = mpf_path
     self.machine_path = machine_path
     self.args = args
     self.mpf = MachineController(
         self.mpf_path, self.machine_path, {
             "bcp": False,
             "no_load_cache": False,
             "mpfconfigfile": os.path.join(mpf_path, "mpfconfig.yaml"),
             "configfile": ["config"],
             "production": False,
             "create_config_cache": False,
             "force_platform": False,
             "text_ui": False
         })
     self.mpf.clock.loop.run_until_complete(
         self.mpf.initialise_core_and_hardware())
     if self.mpf.thread_stopper.is_set():
         raise AssertionError("Initialisation failed!")
Example #9
0
class Command(object):
    """Performs hardware operations."""
    def __init__(self, mpf_path, machine_path, args):
        """Parse args."""
        self.mpf_path = mpf_path
        self.machine_path = machine_path
        self.args = args
        self.mpf = MachineController(
            self.mpf_path, self.machine_path, {
                "bcp": False,
                "no_load_cache": False,
                "mpfconfigfile": os.path.join(mpf_path, "mpfconfig.yaml"),
                "configfile": ["config"],
                "production": False,
                "create_config_cache": False,
                "force_platform": False,
                "text_ui": False
            })
        self.mpf.clock.loop.run_until_complete(
            self.mpf.initialise_core_and_hardware())
        if self.mpf.thread_stopper.is_set():
            raise AssertionError("Initialisation failed!")

    def scan(self):
        """Scan hardware."""
        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.get_info_string())
            print("---------")

        self.mpf.shutdown()

    def firmware_update(self):
        """Upgrade firmware of platforms."""
        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.update_firmware())
            print("---------")

        self.mpf.shutdown()
Example #10
0
    def device_class_init(cls, machine: MachineController):
        """Initialise all LEDs.

        Args:
            machine: MachineController which is used
        """
        cls.machine = machine
        cls.leds_to_fade = set()
        cls.leds_to_update = set()

        machine.validate_machine_config_section('led_settings')

        if machine.config['led_settings']['color_correction_profiles'] is None:
            machine.config['led_settings']['color_correction_profiles'] = (
                dict())

        # Generate and add color correction profiles to the machine
        machine.led_color_correction_profiles = dict()

        # Create the default color correction profile and add it to the machine
        default_profile = RGBColorCorrectionProfile.default()
        machine.led_color_correction_profiles['default'] = default_profile

        # Add any user-defined profiles specified in the machine config file
        for profile_name, profile_parameters in (
                machine.config['led_settings']
            ['color_correction_profiles'].items()):

            machine.config_validator.validate_config(
                'color_correction_profile', machine.config['led_settings']
                ['color_correction_profiles'][profile_name],
                profile_parameters)

            profile = RGBColorCorrectionProfile(profile_name)
            profile.generate_from_parameters(
                gamma=profile_parameters['gamma'],
                whitepoint=profile_parameters['whitepoint'],
                linear_slope=profile_parameters['linear_slope'],
                linear_cutoff=profile_parameters['linear_cutoff'])
            machine.led_color_correction_profiles[profile_name] = profile

        # schedule the single machine-wide update to write the current led of
        # each LED to the hardware
        cls._updater_task = machine.clock.schedule_interval(
            cls.update_leds,
            1 / machine.config['mpf']['default_led_hw_update_hz'])

        machine.mode_controller.register_stop_method(cls.mode_stop)

        machine.settings.add_setting(
            SettingEntry("brightness", "Brightness", 100, "brightness", 1.0, {
                0.25: "25%",
                0.5: "50%",
                0.75: "75%",
                1.0: "100% (default)"
            }))
Example #11
0
File: game.py Project: unRARed/mpf
    def __init__(self, mpf_path, machine_path, args):
        """Run mpf game."""
        signal.signal(signal.SIGINT, self.exit)

        parser = argparse.ArgumentParser(
            description='Starts the MPF game engine')

        parser.add_argument("-a",
                            action="store_true",
                            dest="no_load_cache",
                            help="Forces the config to be loaded from files "
                            "and not cache")

        parser.add_argument("-A",
                            action="store_false",
                            dest="create_config_cache",
                            help="Does not create the cache config files")

        parser.add_argument("-b",
                            action="store_false",
                            dest="bcp",
                            default=True,
                            help="Runs MPF without making a connection "
                            "attempt to a "
                            "BCP Server")

        parser.add_argument("-c",
                            action="store",
                            dest="configfile",
                            default="config.yaml",
                            metavar='config_file',
                            help="The name of a config file to load. Default "
                            "is "
                            "config.yaml. Multiple files can be used "
                            "via a comma-"
                            "separated list (no spaces between)")

        parser.add_argument("-C",
                            action="store",
                            dest="mpfconfigfile",
                            default=os.path.join(mpf_path, "mpfconfig.yaml"),
                            metavar='config_file',
                            help="The MPF framework default config file. "
                            "Default is "
                            "mpf/mpfconfig.yaml")

        parser.add_argument("-f",
                            action="store_true",
                            dest="force_assets_load",
                            default=False,
                            help="Load all assets upon startup.  Useful for "
                            "ensuring all assets are set up properly "
                            "during development.")

        parser.add_argument(
            "-l",
            action="store",
            dest="logfile",
            metavar='file_name',
            default=os.path.join(
                "logs",
                datetime.now().strftime("%Y-%m-%d-%H-%M-%S-mpf-" +
                                        socket.gethostname() + ".log")),
            help="The name (and path) of the log file")

        parser.add_argument("-p",
                            action="store_true",
                            dest="pause",
                            default=False,
                            help="Pause the terminal window on exit. Useful "
                            "when launching in a separate window so you can "
                            "see any errors before the window closes.")

        parser.add_argument(
            "-P",
            action="store_true",
            dest="production",
            default=False,
            help=
            "Production mode. Will suppress errors, wait for hardware on start and "
            "try to exit when startup fails. Run this inside a loop.")

        parser.add_argument("-t",
                            action="store_false",
                            dest='text_ui',
                            default=True,
                            help="Use the ASCII test-based UI")

        parser.add_argument("-v",
                            action="store_const",
                            dest="loglevel",
                            const=logging.DEBUG,
                            default=15,
                            help="Enables verbose logging to the"
                            " log file")

        parser.add_argument(
            "-V",
            action="store_const",
            dest="consoleloglevel",
            const=logging.DEBUG,
            default=logging.INFO,
            help="Enables verbose logging to the console. DO "
            "NOTE: On Windows platforms you must also use -v for "
            "this to work.")

        parser.add_argument("-x",
                            action="store_const",
                            dest="force_platform",
                            const='virtual',
                            help="Forces the virtual platform to be "
                            "used for all devices")

        parser.add_argument("--syslog_address",
                            action="store",
                            dest="syslog_address",
                            help="Log to the specified syslog address. This "
                            "can be a domain socket such as /dev/og on "
                            "Linux or /var/run/syslog on Mac. "
                            "Alternatively, you an specify host:port for "
                            "remote logging over UDP.")

        parser.add_argument("-X",
                            action="store_const",
                            dest="force_platform",
                            const='smart_virtual',
                            help="Forces the smart virtual platform to be "
                            "used for all"
                            " devices")

        # The following are just included for full compatibility with mc
        # which is needed when using "mpf both".

        parser.add_argument("-L",
                            action="store",
                            dest="mc_file_name",
                            metavar='mc_file_name',
                            default=None,
                            help=argparse.SUPPRESS)

        self.args = parser.parse_args(args)
        self.args.configfile = Util.string_to_list(self.args.configfile)

        # Configure logging. Creates a logfile and logs to the console.
        # Formatting options are documented here:
        # https://docs.python.org/2.7/library/logging.html#logrecord-attributes

        try:
            os.makedirs(os.path.join(machine_path, 'logs'))
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise

        full_logfile_path = os.path.join(machine_path, self.args.logfile)

        try:
            os.remove(full_logfile_path)
        except OSError:
            pass

        if self.args.text_ui:
            console_log = logging.NullHandler()
            console_log.setLevel(logging.ERROR)
        else:
            console_log = logging.StreamHandler()
            console_log.setLevel(self.args.consoleloglevel)

        # tell the handler to use this format
        console_log.setFormatter(
            logging.Formatter('%(levelname)s : %(name)s : %(message)s'))

        # initialise async handler for console
        console_log_queue = Queue()
        console_queue_handler = QueueHandler(console_log_queue)
        self.console_queue_listener = logging.handlers.QueueListener(
            console_log_queue, console_log)
        self.console_queue_listener.start()

        # initialise file log
        file_log = logging.FileHandler(full_logfile_path)
        file_log.setFormatter(
            logging.Formatter(
                '%(asctime)s : %(levelname)s : %(name)s : %(message)s'))

        # initialise async handler for file log
        file_log_queue = Queue()
        file_queue_handler = QueueHandler(file_log_queue)
        self.file_queue_listener = logging.handlers.QueueListener(
            file_log_queue, file_log)
        self.file_queue_listener.start()

        # add loggers
        logger = logging.getLogger()
        logger.addHandler(console_queue_handler)
        logger.addHandler(file_queue_handler)
        logger.setLevel(self.args.loglevel)

        if self.args.syslog_address:
            try:
                host, port = self.args.syslog_address.split(":")
            except ValueError:
                syslog_logger = SysLogHandler(self.args.syslog_address)
            else:
                syslog_logger = SysLogHandler((host, int(port)))

            logger.addHandler(syslog_logger)

        try:
            MachineController(mpf_path, machine_path, vars(self.args)).run()
            logging.info("MPF run loop ended.")
            self.exit()

        # pylint: disable-msg=broad-except
        except Exception as e:
            self.exit(exception=e)
Example #12
0
class Command:
    """Runs the mpf game."""

    # pylint: disable-msg=too-many-locals,too-many-statements
    def __init__(self, mpf_path, machine_path, args):
        """Run mpf game."""
        del mpf_path
        self.machine = None
        self._sigint_count = 0

        parser = argparse.ArgumentParser(
            description='Starts the MPF game engine')

        parser.add_argument("-a",
                            action="store_true",
                            dest="no_load_cache",
                            help="Forces the config to be loaded from files "
                            "and not cache")

        parser.add_argument("-A",
                            action="store_false",
                            dest="create_config_cache",
                            help="Does not create the cache config files")

        parser.add_argument("-b",
                            action="store_false",
                            dest="bcp",
                            default=True,
                            help="Runs MPF without making a connection "
                            "attempt to a "
                            "BCP Server")

        parser.add_argument("-c",
                            action="store",
                            dest="configfile",
                            default="config.yaml",
                            metavar='config_file',
                            help="The name of a config file to load. Default "
                            "is "
                            "config.yaml. Multiple files can be used "
                            "via a comma-"
                            "separated list (no spaces between)")

        parser.add_argument("-f",
                            action="store_true",
                            dest="force_assets_load",
                            default=False,
                            help="Load all assets upon startup.  Useful for "
                            "ensuring all assets are set up properly "
                            "during development.")

        parser.add_argument("--json-logging",
                            action="store_true",
                            dest="jsonlogging",
                            default=False,
                            help="Enables json logging to file. ")

        parser.add_argument(
            "-l",
            action="store",
            dest="logfile",
            metavar='file_name',
            default=os.path.join(
                "logs",
                datetime.now().strftime("%Y-%m-%d-%H-%M-%S-mpf-" +
                                        socket.gethostname() + ".log")),
            help="The name (and path) of the log file")

        parser.add_argument("-p",
                            action="store_true",
                            dest="pause",
                            default=False,
                            help="Pause the terminal window on exit. Useful "
                            "when launching in a separate window so you can "
                            "see any errors before the window closes.")

        parser.add_argument(
            "-P",
            action="store_true",
            dest="production",
            default=False,
            help=
            "Production mode. Will suppress errors, wait for hardware on start and "
            "try to exit when startup fails. Run this inside a loop.")

        parser.add_argument("-t",
                            action="store_false",
                            dest='text_ui',
                            default=True,
                            help="Use the ASCII test-based UI")

        parser.add_argument("-v",
                            action="store_const",
                            dest="loglevel",
                            const=logging.DEBUG,
                            default=15,
                            help="Enables verbose logging to the"
                            " log file")

        parser.add_argument(
            "-V",
            action="store_const",
            dest="consoleloglevel",
            const=logging.DEBUG,
            default=logging.INFO,
            help="Enables verbose logging to the console. DO "
            "NOTE: On Windows platforms you must also use -v for "
            "this to work.")

        parser.add_argument("-x",
                            action="store_const",
                            dest="force_platform",
                            const='virtual',
                            help="Forces the virtual platform to be "
                            "used for all devices")

        parser.add_argument("--vpx",
                            action="store_const",
                            dest="force_platform",
                            const='virtual_pinball',
                            help="Forces the virtual_pinball platform to be "
                            "used for all devices")

        parser.add_argument("--syslog_address",
                            action="store",
                            dest="syslog_address",
                            help="Log to the specified syslog address. This "
                            "can be a domain socket such as /dev/og on "
                            "Linux or /var/run/syslog on Mac. "
                            "Alternatively, you an specify host:port for "
                            "remote logging over UDP.")

        parser.add_argument("-X",
                            action="store_const",
                            dest="force_platform",
                            const='smart_virtual',
                            help="Forces the smart virtual platform to be "
                            "used for all"
                            " devices")

        # The following are just included for full compatibility with mc
        # which is needed when using "mpf both".

        parser.add_argument("-L",
                            action="store",
                            dest="mc_file_name",
                            metavar='mc_file_name',
                            default=None,
                            help=argparse.SUPPRESS)

        parser.add_argument("--no-sound",
                            action="store_true",
                            dest="no_sound",
                            default=False)

        self.args = parser.parse_args(args)
        self.args.configfile = Util.string_to_event_list(self.args.configfile)

        # Configure logging. Creates a logfile and logs to the console.
        # Formatting options are documented here:
        # https://docs.python.org/2.7/library/logging.html#logrecord-attributes

        try:
            os.makedirs(os.path.join(machine_path, 'logs'))
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise

        full_logfile_path = os.path.join(machine_path, self.args.logfile)

        try:
            os.remove(full_logfile_path)
        except OSError:
            pass

        if self.args.text_ui:
            console_log = logging.NullHandler()
            console_log.setLevel(logging.ERROR)
        else:
            console_log = logging.StreamHandler()
            console_log.setLevel(self.args.consoleloglevel)

        # tell the handler to use this format
        console_log.setFormatter(
            logging.Formatter('%(levelname)s : %(name)s : %(message)s'))

        # initialise async handler for console
        console_log_queue = Queue()
        console_queue_handler = QueueHandler(console_log_queue)
        self.console_queue_listener = logging.handlers.QueueListener(
            console_log_queue, console_log)
        self.console_queue_listener.start()

        # initialise file log
        file_log = logging.FileHandler(full_logfile_path)
        if self.args.jsonlogging:
            formatter = JSONFormatter()
        else:
            formatter = logging.Formatter(
                '%(asctime)s : %(levelname)s : %(name)s : %(message)s')
        file_log.setFormatter(formatter)

        # initialise async handler for file log
        file_log_queue = Queue()
        file_queue_handler = QueueHandler(file_log_queue)
        self.file_queue_listener = logging.handlers.QueueListener(
            file_log_queue, file_log)
        self.file_queue_listener.start()

        # add loggers
        logger = logging.getLogger()
        logger.addHandler(console_queue_handler)
        logger.addHandler(file_queue_handler)
        logger.setLevel(self.args.loglevel)
        logger.info("Loading config.")

        if self.args.syslog_address:
            try:
                host, port = self.args.syslog_address.split(":")
            except ValueError:
                syslog_logger = SysLogHandler(self.args.syslog_address)
            else:
                syslog_logger = SysLogHandler((host, int(port)))

            logger.addHandler(syslog_logger)

        signal.signal(signal.SIGINT, self.sigint_handler)

        if not self.args.production:
            config_loader = YamlMultifileConfigLoader(
                machine_path, self.args.configfile,
                not self.args.no_load_cache, self.args.create_config_cache)
        else:
            config_loader = ProductionConfigLoader(machine_path)

        try:
            config = config_loader.load_mpf_config()
        except ConfigFileError as e:
            print("Error while parsing config: {}", e)
            report_crash(e, "config_parsing", {})
            self.exit()

        try:
            self.machine = MachineController(vars(self.args), config)
            self.machine.add_crash_handler(self.restore_logger)
            self.machine.run()
            logging.info("MPF run loop ended.")
            self.exit()

        # pylint: disable-msg=broad-except
        except Exception as e:
            self.exit(exception=e)

    def sigint_handler(self, signum=None, frame=None):
        """Handle SIGINT."""
        del signum, frame
        self._sigint_count += 1
        if self._sigint_count > 1:
            self.exit("Received second SIGINT. Will exit ungracefully!")
        elif self.machine:
            self.machine.stop("SIGINT or keyboard interrupt")
        else:
            self.exit("Shutdown because of SIGINT or keyboard interrupt.")

    def restore_logger(self):
        """Restore logger."""
        if self.args.text_ui:
            # Re-enable console logging
            logger = logging.getLogger()
            logger.addHandler(logging.StreamHandler())

    def exit(self, exception=None):
        """Handle MPF exit from either a clean shutdown or from a crash.

        Cleanly shuts down logging and restores the console window if the Text
        UI option is used.
        """
        if exception:
            logging.exception(exception)

        logging.shutdown()
        self.console_queue_listener.stop()
        self.file_queue_listener.stop()

        if self.args.pause:
            input('Press ENTER to continue...')  # nosec

        sys.exit()
Example #13
0
import logging
import sys
from mpf.core.config_loader import YamlMultifileConfigLoader

from mpf.core.machine import MachineController

machine_path = sys.argv[1]

config_loader = YamlMultifileConfigLoader(machine_path, ["config.yaml"], False,
                                          False)
config = config_loader.load_mpf_config()

options = {
    'force_platform': 'smart_virtual',
    'production': False,
    'mpfconfigfile': ["mpfconfig.yaml"],
    'configfile': ["config.yaml"],
    'debug': True,
    'bcp': True,
    'no_load_cache': False,
    'create_config_cache': True,
    'text_ui': False,
    'consoleloglevel': logging.DEBUG,
}
logging.basicConfig(level=logging.DEBUG)
machine = MachineController(options, config)
machine.run()
Example #14
0
    def __init__(self, mpf_path, machine_path, args):
        """Run mpf game."""
        parser = argparse.ArgumentParser(
            description='Starts the MPF game engine')

        parser.add_argument("-c",
                            action="store",
                            dest="configfile",
                            default="config",
                            metavar='config_file',
                            help="The name of a config file to load. Default "
                            "is "
                            "config.yaml. Multiple files can be used "
                            "via a comma-"
                            "separated list (no spaces between)")

        parser.add_argument("-v",
                            action="store_const",
                            dest="loglevel",
                            const=logging.DEBUG,
                            default=logging.INFO,
                            help="Enables verbose logging to the"
                            " log file")

        parser.add_argument("-V",
                            action="store_true",
                            dest="consoleloglevel",
                            default=logging.INFO,
                            help="Enables verbose logging to the console. Do "
                            "NOT on "
                            "Windows platforms. Must also use -v for "
                            "this to work.")

        parser.add_argument("-x",
                            action="store_const",
                            dest="force_platform",
                            const='virtual',
                            help="Forces the virtual platform to be "
                            "used for all devices")

        parser.add_argument("-a",
                            action="store_true",
                            dest="no_load_cache",
                            help="Forces the config to be loaded from files "
                            "and not "
                            "cache")

        parser.add_argument("-A",
                            action="store_false",
                            dest="create_config_cache",
                            help="Does not create the cache config files")

        parser.add_argument("-X",
                            action="store_const",
                            dest="force_platform",
                            const='smart_virtual',
                            help="Forces the smart virtual platform to be "
                            "used for all"
                            " devices")

        parser.add_argument("-b",
                            action="store_false",
                            dest="bcp",
                            default=True,
                            help="Runs MPF without making a connection "
                            "attempt to a "
                            "BCP Server")

        parser.add_argument(
            "-l",
            action="store",
            dest="logfile",
            metavar='file_name',
            default=os.path.join(
                "logs",
                datetime.now().strftime("%Y-%m-%d-%H-%M-%S-mpf-" +
                                        socket.gethostname() + ".log")),
            help="The name (and path) of the log file")

        parser.add_argument("-C",
                            action="store",
                            dest="mpfconfigfile",
                            default=os.path.join(mpf_path, "mpfconfig.yaml"),
                            metavar='config_file',
                            help="The MPF framework default config file. "
                            "Default is "
                            "mpf/mpfconfig.yaml")

        parser.add_argument("-p",
                            action="store_true",
                            dest="pause",
                            default=False,
                            help="Pause the terminal window on exit. Useful "
                            "when launching in a separate window so you can "
                            "see any errors before the window closes.")

        parser.add_argument("-f",
                            action="store_true",
                            dest="force_assets_load",
                            default=False,
                            help="Load all assets upon startup.  Useful for "
                            "ensuring all assets are set up properly "
                            "during development.")

        args = parser.parse_args(args)
        args.configfile = Util.string_to_list(args.configfile)

        # Configure logging. Creates a logfile and logs to the console.
        # Formatting options are documented here:
        # https://docs.python.org/2.7/library/logging.html#logrecord-attributes

        try:
            os.makedirs(os.path.join(machine_path, 'logs'))
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise

        logging.basicConfig(level=args.loglevel,
                            format='%(asctime)s : %(levelname)s : %(name)s : '
                            '%(message)s',
                            filename=os.path.join(machine_path, args.logfile),
                            filemode='w')

        # define a Handler which writes INFO messages or higher to the
        # sys.stderr
        console = logging.StreamHandler()
        console.setLevel(args.consoleloglevel)

        # set a format which is simpler for console use
        formatter = logging.Formatter('%(levelname)s : %(name)s : %(message)s')

        # tell the handler to use this format
        console.setFormatter(formatter)

        # add the handler to the root logger
        logging.getLogger('').addHandler(console)

        try:
            MachineController(mpf_path, machine_path, vars(args)).run()
            logging.info("MPF run loop ended.")
        # pylint: disable-msg=broad-except
        except Exception as e:
            logging.exception(e)

        if args.pause:
            input('Press ENTER to continue...')
        sys.exit()
Example #15
0
class Command(MpfCommandLineParser):
    """Performs hardware operations."""
    def __init__(self, args, path):
        """Parse args."""
        command_name = args.pop(1)
        super().__init__(args=args, path=path)

        machine_path, remaining_args = self.parse_args()
        self.machine_path = machine_path
        self.args = remaining_args
        config_loader = YamlMultifileConfigLoader(machine_path,
                                                  ["config.yaml"], True, False)

        config = config_loader.load_mpf_config()

        self.mpf = MachineController(
            {
                "bcp": False,
                "no_load_cache": False,
                "mpfconfigfile": os.path.join(self.mpf_path, "mpfconfig.yaml"),
                "configfile": ["config"],
                "production": False,
                "create_config_cache": False,
                "force_platform": False,
                "text_ui": False
            }, config)

        method = getattr(self, command_name)
        method()

    def scan(self):
        """Scan hardware."""
        self.mpf.clock.loop.run_until_complete(
            self.mpf.initialise_core_and_hardware())
        if self.mpf.thread_stopper.is_set():
            raise AssertionError("Initialisation failed!")

        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.get_info_string())
            print("---------")

        self.mpf.shutdown()

    def firmware_update(self):
        """Upgrade firmware of platforms."""
        self.mpf.clock.loop.run_until_complete(
            self.mpf.initialise_core_and_hardware())
        if self.mpf.thread_stopper.is_set():
            raise AssertionError("Initialisation failed!")

        for name, platform in self.mpf.hardware_platforms.items():
            print("{}:".format(name))
            print(platform.update_firmware())
            print("---------")

        self.mpf.shutdown()

    # pylint: disable-msg=too-many-locals
    def _test_repeated_pulses_with_rule(self, config, pulse_ms, pause_min,
                                        pause_max):
        latency = []
        rule_latency = []
        pulse_duration = []
        rule_pulse_duration = []
        timeouts = 0

        config["flipper"].enable()

        for _ in range(100):
            # measure coil -> input latency
            pulse_start = time.time()
            config["coil1"].pulse(pulse_ms=pulse_ms)

            try:
                self.mpf.clock.loop.run_until_complete(
                    asyncio.wait_for(
                        self.mpf.switch_controller.wait_for_switch(
                            config["switch1"], state=1, only_on_change=False),
                        timeout=.5))
                switch_active = time.time()
                self.mpf.clock.loop.run_until_complete(
                    asyncio.wait_for(
                        self.mpf.switch_controller.wait_for_switch(
                            config["switch2"], state=1, only_on_change=False),
                        timeout=.5))
                switch2_active = time.time()

                self.mpf.clock.loop.run_until_complete(
                    asyncio.wait_for(
                        self.mpf.switch_controller.wait_for_switch(
                            config["switch1"], state=0, only_on_change=False),
                        timeout=.5))
                switch_inactive = time.time()
                self.mpf.clock.loop.run_until_complete(
                    asyncio.wait_for(
                        self.mpf.switch_controller.wait_for_switch(
                            config["switch2"], state=0, only_on_change=False),
                        timeout=.5))
                switch2_inactive = time.time()
            except asyncio.TimeoutError:
                print(
                    "WARNING: Ran into timeout while waiting. Check your setup!"
                )
                timeouts += 1
                continue

            self.mpf.clock.loop.run_until_complete(
                asyncio.sleep(
                    random.uniform(pause_min * 0.001, pause_max * 0.001)))

            latency.append((switch_active - pulse_start) * 1000)
            rule_latency.append((switch2_active - switch_active) * 1000)
            pulse_duration.append((switch_inactive - switch_active) * 1000)
            rule_pulse_duration.append(
                (switch2_inactive - switch2_active) * 1000)

        print(
            "----------------------------------------------------------------------------------------"
        )
        print("Pulse duration: {}ms Pause: {}ms to {}ms".format(
            pulse_ms, pause_min, pause_max))
        print(
            "Latency mean: {:.2f} median: {:.2f} min: {:.2f} max: {:.2f} stdev: {:.2f} variance: {:.2f}"
            .format(statistics.mean(latency), statistics.median(latency),
                    min(latency), max(latency), statistics.stdev(latency),
                    statistics.variance(latency)))
        print(
            "Rule Latency mean: {:.2f} median: {:.2f} min: {:.2f} max: {:.2f} stdev: {:.2f} variance: {:.2f}"
            .format(statistics.mean(rule_latency),
                    statistics.median(rule_latency), min(rule_latency),
                    max(rule_latency), statistics.stdev(rule_latency),
                    statistics.variance(rule_latency)))
        print(
            "Pulse duration measured mean: {:.2f} median: {:.2f} min: {:.2f} max: {:.2f} stdev: {:.2f} "
            "variance: {:.2f}".format(statistics.mean(pulse_duration),
                                      statistics.median(pulse_duration),
                                      min(pulse_duration), max(pulse_duration),
                                      statistics.stdev(pulse_duration),
                                      statistics.variance(pulse_duration)))
        print(
            "Rule Pulse duration measured mean: {:.2f} median: {:.2f} min: {:.2f} max: {:.2f} stdev: {:.2f} "
            "variance: {:.2f}".format(
                statistics.mean(rule_pulse_duration),
                statistics.median(rule_pulse_duration),
                min(rule_pulse_duration), max(rule_pulse_duration),
                statistics.stdev(rule_pulse_duration),
                statistics.variance(rule_pulse_duration)))
        if timeouts:
            print(
                "Warning: Experienced {} timeouts during benchmark. Check your setup!"
                .format(timeouts))
        print(
            "----------------------------------------------------------------------------------------"
        )
        print()

        config["flipper"].disable()

    def benchmark(self):
        """Benchmark hardware."""
        self.mpf.clock.loop.run_until_complete(self.mpf.initialise())
        if self.mpf.thread_stopper.is_set():
            raise AssertionError("Initialisation failed!")

        print(self.mpf.switches, self.mpf.coils)
        config = self.mpf.config_validator.validate_config(
            "hardware_benchmark", self.mpf.config.get("hardware_benchmark",
                                                      {}))
        print(
            "1. Please confirm that you connected driver \"{}\" to switch \"{}\" and "
            "driver \"{}\" to switch \"{}\"".format(config["coil1"],
                                                    config["switch1"],
                                                    config["coil2"],
                                                    config["switch2"]))
        print("2. Turn off high voltage!")
        print(
            "3. Hardware test will repeatedly pulse driver \"{}\" and \"{}\". "
            "Make sure they are not connected to coils and cannot cause any harm."
            .format(config["coil1"], config["coil2"]))
        print("4. Turn off high voltage! (seriously)")
        print("")

        input_text = input(
            "I am certain and know what I am doing (type YES if you are certain): "
        )
        if input_text != "YES":
            print("Wrong input. Exiting!")
            self.mpf.shutdown()
            return

        input_text = input(
            "I did turn off high voltage (type HIGH VOLTAGE IS OFF): ")
        if input_text != "HIGH VOLTAGE IS OFF":
            print("Wrong input. Exiting!")
            self.mpf.shutdown()
            return

        print()
        print("This will take a few seconds. Please standby!")
        print()

        if config["flipper"].config["main_coil"] != config["coil2"]:
            print("Main_coil on flipper {} should be {} but is {}.".format(
                config["flipper"], config["coil2"],
                config["flipper"].config["main_coil"]))
            self.mpf.shutdown()
            return

        if config["flipper"].config["activation_switch"] != config["switch1"]:
            print("Activation_switch on flipper {} should be {} but is {}.".
                  format(config["flipper"], config["switch1"],
                         config["flipper"].config["activation_switch"]))
            self.mpf.shutdown()
            return

        if config["switch1"].state != 0:
            print("Switch {} should be inactive but is active.".format(
                config["switch1"]))
            self.mpf.shutdown()
            return

        if config["switch2"].state != 0:
            print("Switch {} should be inactive but is active.".format(
                config["switch2"]))
            self.mpf.shutdown()
            return

        # let the platform settle
        self.mpf.clock.loop.run_until_complete(asyncio.sleep(.5))

        self._test_repeated_pulses_with_rule(config, 53, 50, 100)
        self.mpf.clock.loop.run_until_complete(asyncio.sleep(.5))
        self._test_repeated_pulses_with_rule(config, 23, 5, 20)
        self.mpf.clock.loop.run_until_complete(asyncio.sleep(.5))
        self._test_repeated_pulses_with_rule(config, 13, 1, 2)

        self.mpf.shutdown()