diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000..f154fd960c --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,22 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version, and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + +# Build documentation with Mkdocs +mkdocs: + configuration: mkdocs.yml + +# Optionally, but recommended, +# declare the Python requirements required to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: requirements.txt diff --git a/docs/code/BCP_Protocol/ball_end.md b/docs/code/BCP_Protocol/ball_end.md new file mode 100644 index 0000000000..172fb162ba --- /dev/null +++ b/docs/code/BCP_Protocol/ball_end.md @@ -0,0 +1,15 @@ + +## ball_end (BCP command) + +Indicates the ball has ended. Note that this does not necessarily mean that the next player’s turn will start, as this player may have an extra ball which means they’ll shoot again. + +## Origin +Pin controller + +## Parameters +None + +## Response + +None + diff --git a/docs/code/BCP_Protocol/ball_start.md b/docs/code/BCP_Protocol/ball_start.md new file mode 100644 index 0000000000..e31893ab4c --- /dev/null +++ b/docs/code/BCP_Protocol/ball_start.md @@ -0,0 +1,21 @@ + +# ball_start (BCP command) + +Indicates a new ball has started. It passes the player number (1, 2, etc.) and the ball number as parameters. This command will be sent every time a ball starts, even if the same player is shooting again after an extra ball. + +## Origin +Pin controller + +## Parameters +### player_num +Type: `int` + +The player number. + +### ball +Type: `int` + +The ball number. + +## Response +None diff --git a/docs/code/BCP_Protocol/device.md b/docs/code/BCP_Protocol/device.md new file mode 100644 index 0000000000..9737cdf326 --- /dev/null +++ b/docs/code/BCP_Protocol/device.md @@ -0,0 +1,30 @@ + +# device (BCP command) + +## Origin +Pin controller or media controller + +## Parameters +### type + +Type: `string` + +The type/class of device (ex: coil). + +### name +Type: `string` + +The name of the device. + +### changes +Type: `tuple` (attribute name, old value, new value) + +The change to the device state. + +### state +Type: varies (depending upon device type) + +The device state. + +## Response +None diff --git a/docs/code/BCP_Protocol/error.md b/docs/code/BCP_Protocol/error.md new file mode 100644 index 0000000000..e9832b21e3 --- /dev/null +++ b/docs/code/BCP_Protocol/error.md @@ -0,0 +1,20 @@ + +# error (BCP command) +This is a command used to convey error messages back to the origin of a command. + +## Origin +Pin controller or media controller + +## Parameters +### message +Type: `string` + +The error message. + +### command +Type: `string` + +The command that was invalid and caused the error. + +## Response +None diff --git a/docs/code/BCP_Protocol/goodbye.md b/docs/code/BCP_Protocol/goodbye.md new file mode 100644 index 0000000000..699e0cfa9b --- /dev/null +++ b/docs/code/BCP_Protocol/goodbye.md @@ -0,0 +1,12 @@ + +# goodbye (BCP command) +Lets one side tell the other than it’s shutting down. + +## Origin +Pin controller or media controller + +## Parameters +None + +## Response +None diff --git a/docs/code/BCP_Protocol/hello.md b/docs/code/BCP_Protocol/hello.md new file mode 100644 index 0000000000..91597d3692 --- /dev/null +++ b/docs/code/BCP_Protocol/hello.md @@ -0,0 +1,26 @@ + +# hello (BCP command) +This is the initial handshake command upon first connection. It sends the BCP protocol version that the origin controller speaks. + +## Origin +Pin controller or media controller + +## Parameters +### version +Type: `string` + +The BCP communication specification version implemented in the controller (ex: 1.0). + +### controller_name +Type: `string` + +The name of the controller (ex: Mission Pinball Framework). + +### controller_version +Type: `string` + +The version of the controller (ex: 0.33.0). + +## Response + +When received by the media controller, this command automatically triggers a hard “reset”. If the pin controller is sending this command, the media controller will respond with either its own “hello” command, or the error “unknown protocol version.” The pin controller should never respond to this command when it receives it from the media controller; that would trigger an infinite loop. diff --git a/docs/code/BCP_Protocol/index.md b/docs/code/BCP_Protocol/index.md new file mode 100644 index 0000000000..6cc4c0787c --- /dev/null +++ b/docs/code/BCP_Protocol/index.md @@ -0,0 +1,97 @@ + +# BCP Protocol Specification + +This document describes the Backbox Control Protocol, (or “BCP”), a simple, fast protocol for communications between an implementation of a pinball game controller and a multimedia controller. + +!!! note + + BCP is how the MPF core engine and the MPF media controller communicate. + +BCP transmits semantically relevant information and attempts to isolate specific behaviors and identifiers on both sides. i.e., the pin controller is responsible for telling the media controller “start multiball mode”. The pin controller doesn’t care what the media controller does with that information, and the media controller doesn’t care what happened on the pin controller that caused the multiball mode to start. + +BCP is versioned to prevent conflicts. Future versions of the BCP will be designed to be backward compatible to every degree possible. The reference implementation uses a raw TCP socket for communication. On localhost the latency is usually sub-millisecond and on LANs it is under 10 milliseconds. That means that the effect of messages is generally under 1/100th of a second, which should be considered instantaneous from the perspective of human perception. + +It is important to note that this document specifies the details of the protocol itself, not necessarily the behaviors of any specific implementations it connects. Thus, there won’t be details about fonts or sounds or images or videos or shaders here; those are up to specific implementation being driven. + +!!! warning "Infinite Loops Possible" + + Since the pin controller and media controller are both state machines synchronized through the use of commands, it is possible for the programmer to inadvertently set up infinite loops. These can be halted with the [reset](reset.md) command or [hello](hello.md) described below. + + +## Background + +While the BCP protocol was created as part of the MPF project, the intention is that BCP is an open protocol that could connect any pinball controller to any media controller. + + +## Protocol Format + +* Commands are human-readable text in a format similar to URLs, e.g. `command?parameter1=value¶meter2=value` +* Command characters are encoded with the utf-8 character encoding. This allows ad-hoc text for languages that use characters past ASCII-7 bit, such as Japanese Kanji. +* Command and parameter names are whitespace-trimmed on both ends by the recipient +* Commands are case-insensitive +* Parameters are optional. If present, a question mark separates the command from its parameters +* Parameters are in the format `name=value` +* Parameter names are case-insensitive +* Parameter values are case-sensitive +* Simple parameter values are prefixed with a string that indicates their data type: (`int:`, `float:`, `bool:`, `NoneType:`). For example, the integer 5 would appear in the command string as `int:5`. +* When a command includes one or more complex value types (list or dict) all parameters are encoded using JSON and the resulting encoded value is assigned to the `json:` parameter. +* Parameters are separated by an ampersand (`&`) +* Parameter names and their values are escaped using percent encoding as necessary; (details here). +* Commands are terminated by a line feed character (`\n`). Carriage return characters (`\r`) should be tolerated but are not significant. +* A blank line (no command) is ignored +* Commands beginning with a hash character (`#`) are ignored +* If a command passes unknown parameters, the recipient should ignore them. +* The pinball controller and the media controller must be resilient to network problems; if a connection is lost, it can simply re-open it to resume operation. There is no requirement to buffer unsendable commands to transmit on reconnection. +* Once initial handshaking has completed on the first connection, subsequent re-connects do not have to handshake again. +* An unrecognized command results in an error response with the message “unknown command” + +In all commands referenced below, the `\n` terminator is implicit. Some characters in parameters such as spaces would really be encoded as `%20` (space) in operation, but are left unencoded here for clarity. + +## Initial Handshake + +When a connection is initially established, the pinball controller transmits the following command: + +``` +hello?version=1.0 +``` + +…where 1.0 is the version of the Backbox protocol it wants to speak. The media controller may reply with one of two responses: + +``` +hello?version=1.0 +``` + +…indicating that it can speak the protocol version named, and reporting the version it speaks, or + +``` +error?message=unknown protocol version +``` + +…indicating that it cannot. How the pin controller handles this situation is implementation-dependent. + +## BCP commands + +The following BCP commands have been defined (and implemented) in MPF: + +* [ball_end](ball_end.md) +* [ball_start](ball_start.md) +* [device](device.md) +* [error](error.md) +* [goodbye](goodbye.md) +* [hello](hello.md) +* [machine_variable](machine_variable.md) +* [mode_start](mode_start.md) +* [mode_stop](mode_stop.md) +* [monitor_start](monitor_start.md) +* [monitor_stop](monitor_stop.md) +* [player_added](player_added.md) +* [player_turn_start](player_turn_start.md) +* [player_variable](player_variable.md) +* [register_trigger](register_trigger.md) +* [remove_trigger](remove_trigger.md) +* [reset](reset.md) +* [reset_complete](reset_complete.md) +* [switch](switch.md) +* [trigger](trigger.md) + + diff --git a/docs/code/BCP_Protocol/machine_variable.md b/docs/code/BCP_Protocol/machine_variable.md new file mode 100644 index 0000000000..48bc57e80d --- /dev/null +++ b/docs/code/BCP_Protocol/machine_variable.md @@ -0,0 +1,30 @@ + +# machine_variable (BCP command) +This is a generic “catch all” which sends machine variables to the media controller any time they change. Machine variables are like player variables, except they’re maintained machine-wide instead of per-player or per-game. Since the pin controller will most likely track hundreds of variables (with many being internal things that the media controller doesn’t care about), it’ s recommended that the pin controller has a way to filter which machine variables are sent to the media controller. + +## Origin +Pin controller + +## Parameters +### name +Type: `string` + +This is the name of the machine variable. + +### value +Type: Varies depending upon the variable type. + +This is the new value of the machine variable. + +### prev_value +Type: Varies depending upon the variable type. + +This is the previous value of the machine variable. + +### change +Type: Varies depending upon the variable type. + +If the machine variable just changed, this will be the amount of the change. If it’s not possible to determine a numeric change (for example, if this machine variable is a string), then this change value will be set to the boolean True. + +## Response +None diff --git a/docs/code/BCP_Protocol/mode_start.md b/docs/code/BCP_Protocol/mode_start.md new file mode 100644 index 0000000000..e05fb17a59 --- /dev/null +++ b/docs/code/BCP_Protocol/mode_start.md @@ -0,0 +1,20 @@ + +# mode_start (BCP command) +A game mode has just started. The mode is passed via the name parameter, and the mode’s priority is passed as an integer via the priority. + +## Origin +Pin controller + +## Parameters +### name +Type: `string` + +The mode name. + +### priority +Type: `int` + +The mode priority. + +## Response +None diff --git a/docs/code/BCP_Protocol/mode_stop.md b/docs/code/BCP_Protocol/mode_stop.md new file mode 100644 index 0000000000..67f20eb1e4 --- /dev/null +++ b/docs/code/BCP_Protocol/mode_stop.md @@ -0,0 +1,16 @@ + +# mode_stop (BCP command) +Indicates the mode has stopped. + +## Origin +Pin controller + +## Parameters +### name + +Type: `string` + +The mode name. + +## Response +None diff --git a/docs/code/BCP_Protocol/monitor_start.md b/docs/code/BCP_Protocol/monitor_start.md new file mode 100644 index 0000000000..fabf8e32dc --- /dev/null +++ b/docs/code/BCP_Protocol/monitor_start.md @@ -0,0 +1,26 @@ + +# monitor_start (BCP command) + +New in version 0.33. + +Request from the media controller to the pin controller to begin monitoring events in the specified category. Events will not be automatically sent to the media controller from the pin controller via BCP unless they are requested using the monitor_start or register_trigger commands. + +## Origin +Media controller + +## Parameters +### category +Single string value, type: one of the following options: events, devices, machine_vars, player_vars, switches, modes, ball, or timer. + +The value of category determines the category of events to begin monitoring. Options for category are: + +* `events` - All events in the pin controller +* `devices` - All device state changes +* `machine_vars` - All machine variable changes +* `player_vars` - All player variable changes +* `switches` - All switch state changes +* `modes` - All mode events (start, stop) +* `core_events` - Core MPF events (ball handing, player turn, etc.) + +## Response +None diff --git a/docs/code/BCP_Protocol/monitor_stop.md b/docs/code/BCP_Protocol/monitor_stop.md new file mode 100644 index 0000000000..68ae580853 --- /dev/null +++ b/docs/code/BCP_Protocol/monitor_stop.md @@ -0,0 +1,26 @@ + +# monitor_stop (BCP command) + +New in version 0.33. + +Request from the media controller to the pin controller to stop monitoring events in the specified category. Once a monitor has been started, events will continue to be automatically sent to the media controller from the pin controller via BCP until they are stopped using the monitor_stop or remove_trigger commands. + +## Origin +Media controller + +## Parameters +### category +Single string value, type: one of the following options: events, devices, machine_vars, player_vars, switches, modes, ball, or timer. + +The value of category determines the category of events to stop monitoring. Options for category are: + +* `events` - All events in the pin controller +* `devices` - All device state changes +* `machine_vars` - All machine variable changes +* `player_vars` - All player variable changes +* `switches` - All switch state changes +* `modes` - All mode events (start, stop) +* `core_events` - Core MPF events (ball handing, player turn, etc.) + +## Response +None diff --git a/docs/code/BCP_Protocol/player_added.md b/docs/code/BCP_Protocol/player_added.md new file mode 100644 index 0000000000..5a13108e2b --- /dev/null +++ b/docs/code/BCP_Protocol/player_added.md @@ -0,0 +1,15 @@ + +# player_added (BCP command) +A player has just been added, with the player number passed via the player_num parameter. Typically these commands only occur during Ball 1. + +## Origin +Pin controller + +## Parameters +### player_num +Type: `int` + +The player number just added. + +## Response +None diff --git a/docs/code/BCP_Protocol/player_turn_start.md b/docs/code/BCP_Protocol/player_turn_start.md new file mode 100644 index 0000000000..4689ecfaef --- /dev/null +++ b/docs/code/BCP_Protocol/player_turn_start.md @@ -0,0 +1,15 @@ + +# player_turn_start (BCP command) +A new player’s turn has begun. If a player has an extra ball, this command will not be sent between balls. However, a new ball_start command will be sent when the same player’s additional balls start. + +## Origin +Pin controller + +## Parameters +### player_num +Type: `int` + +The player number. + +## Response +None diff --git a/docs/code/BCP_Protocol/player_variable.md b/docs/code/BCP_Protocol/player_variable.md new file mode 100644 index 0000000000..87f7b2d537 --- /dev/null +++ b/docs/code/BCP_Protocol/player_variable.md @@ -0,0 +1,36 @@ + +# player_variable (BCP command) + +This is a generic “catch all” which sends player-specific variables to the media controller any time they change. Since the pin controller will most likely track hundreds of variables per player (with many being internal things that the media controller doesn’t care about), it’s recommended that the pin controller has a way to filter which player variables are sent to the media controller. Also note the parameter player_num indicates which player this variable is for (starting with 1 for the first player). While it’s usually the case that the player_variable command will be sent for the player whose turn it is, that’s not always the case. (For example, when a second player is added during the first player’s ball, the second player’s default variables will be initialized at 0 and a player_variable event for player 2 will be sent even though player 1 is up. + +## Origin +Pin controller + +## Parameters +### name +Type: `string` + +This is the name of the player variable. + +### player_num +Type: `int` + +This is the player number the variable is for (starting with 1 for the first player). + +### value +Type: Varies depending upon the variable type. + +This is the new value of the player variable. + +### prev_value +Type: Varies depending upon the variable type. + +This is the previous value of the player variable. + +### change +Type: Varies depending upon the variable type. + +If the player variable just changed, this will be the amount of the change. If it’s not possible to determine a numeric change (for example, if this player variable is a string), then this change value will be set to the boolean True. + +## Response +None diff --git a/docs/code/BCP_Protocol/register_trigger.md b/docs/code/BCP_Protocol/register_trigger.md new file mode 100644 index 0000000000..76f88781fb --- /dev/null +++ b/docs/code/BCP_Protocol/register_trigger.md @@ -0,0 +1,15 @@ + +# register_trigger (BCP command) +Request from the media controller to the pin controller to register an event name as a trigger so it will be sent via BCP to the media controller whenever the event is posted in MPF. + +## Origin +Media controller + +## Parameters +### event +Type: `string` + +This is the name of the trigger event to register with the pin controller. + +## Response +None diff --git a/docs/code/BCP_Protocol/remove_trigger.md b/docs/code/BCP_Protocol/remove_trigger.md new file mode 100644 index 0000000000..0fa01550bd --- /dev/null +++ b/docs/code/BCP_Protocol/remove_trigger.md @@ -0,0 +1,17 @@ + +# remove_trigger (BCP command) +New in version 0.33. + +Request from the media controller to the pin controller to cancel/deregister an event name as a trigger so it will no longer be sent via BCP to the media controller whenever the event is posted in MPF. + +##Origin +Media controller + +## Parameters +### event +Type: `string` + +This is the name of the trigger event to cancel/deregister with the pin controller. + +## Response +None diff --git a/docs/code/BCP_Protocol/reset.md b/docs/code/BCP_Protocol/reset.md new file mode 100644 index 0000000000..bfef6504c4 --- /dev/null +++ b/docs/code/BCP_Protocol/reset.md @@ -0,0 +1,12 @@ + +# reset (BCP command) +This command notifies the media controller that the pin controller is in the process of performing a reset. If necessary, the media controller should perform its own reset process. The media controller must respond with a [reset_complete](reset_complete.md) command when finished. + +## Origin +Pin controller + +## Parameters +None + +## Response +[reset_complete](reset_complete.md) when reset process has finished diff --git a/docs/code/BCP_Protocol/reset_complete.md b/docs/code/BCP_Protocol/reset_complete.md new file mode 100644 index 0000000000..5cd374cb7a --- /dev/null +++ b/docs/code/BCP_Protocol/reset_complete.md @@ -0,0 +1,12 @@ + +# reset_complete (BCP command) +This command notifies the pin controller that reset process is now complete. It must be sent in response to receiving a [reset](reset.md) command. + +## Origin +Media controller + +## Parameters +None + +## Response +None diff --git a/docs/code/BCP_Protocol/switch.md b/docs/code/BCP_Protocol/switch.md new file mode 100644 index 0000000000..15e736d0f8 --- /dev/null +++ b/docs/code/BCP_Protocol/switch.md @@ -0,0 +1,31 @@ +# switch (BCP command) +Indicates that the other side should process the changed state of a switch. When sent from the media controller to the pin controller, this is typically used to implement a virtual keyboard interface via the media controller (where the player can activate pinball machine switches via keyboard keys for testing). For example, for the media controller to tell the pin controller that the player just pushed the start button, the command would be: + +``` +switch?name=start&state=1 +``` + +followed very quickly by + +``` +switch?name=start&state=0 +``` + +When sent from the pin controller to the media controller, this is used to send switch inputs to things like video modes, high score name entry, and service menu navigation. Note that the pin controller should not send the state of every switch change at all times, as the media controller doesn’t need it and that would add lots of unnecessary commands. Instead the pin controller should only send switches based on some mode of operation that needs them. (For example, when the video mode starts, the pin controller would start sending the switch states of the flipper buttons, and when the video mode ends, it would stop.) + +## Origin +Pin controller or media controller + +## Parameters +## name +Type: `string` + +This is the name of the switch. + +### state +Type: `int` + +The new switch state: 1 for active, and 0 for inactive. + +## Response +None diff --git a/docs/code/BCP_Protocol/trigger.md b/docs/code/BCP_Protocol/trigger.md new file mode 100644 index 0000000000..36c3c0fb64 --- /dev/null +++ b/docs/code/BCP_Protocol/trigger.md @@ -0,0 +1,11 @@ +# trigger (BCP command) +This command allows the one side to trigger the other side to do something. For example, the pin controller might send trigger commands to tell the media controller to start shows, play sound effects, or update the display. The media controller might send a trigger to the pin controller to flash the strobes at the down beat of a music track or to pulse the knocker in concert with a replay show. + +## Origin +Pin controller or media controller + +## Parameters +### name +Type: `string` + +This is the name of the trigger. diff --git a/docs/code/Writing_Tests/RunUnitTests.md b/docs/code/Writing_Tests/RunUnitTests.md new file mode 100644 index 0000000000..9189617996 --- /dev/null +++ b/docs/code/Writing_Tests/RunUnitTests.md @@ -0,0 +1,45 @@ + +# How to run MPF unittests + +Once MPF is installed, you can run some automated tests to make sure that everything is working. To do this, open a command prompt, and then type the following command and then press : + +``` +python3 -m unittest discover mpf/tests +``` + +When you do this, you should see a bunch of dots on the screen (one for each test that’s run), and then when it’s done, you should see a message showing how many tests were run and that they were successful. The whole process should take less a minute or so. + +(If you see any messages about some tests taking more than 0.5s, that’s ok.) + +The important thing is that when the tests are done, you should have a message like this: + +``` +Ran 587 tests in 27.121s + +OK + +C:\> +``` + +Note that the number of tests is changing all the time, so it probably won’t be exactly 587. And also the time they took to run will be different depending on how fast your computer is. + +These tests are the actual tests that the developers of MPF use to test MPF itself. We wrote all these tests to make sure that updates and changes we add to MPF don’t break things. :) So if these tests pass, you know your MPF installation is solid. + +Remember though that MPF is actually two separate parts, the MPF game engine and the MPF media controller. The command you run just tested the game engine, so now let’s test the media controller. To do this, run the following command (basically the same thing as last time but with an “mc” added to the end, like this): + +``` +python3 -m unittest discover mpfmc/tests +``` + +(Note that mpfmc does not have a dash in it, like it did when you installed it via pip.) + +When you run the MPF-MC tests, you should see a graphical window pop up on the screen, and many of the tests will put graphics and words in that window. Also, some of the tests include audio, so if your speakers are on you should hear some sounds at some point. + +These tests take significantly longer (maybe 8x) than the MPF tests, but when they’re done, that graphical window should close, and you’ll see all the dots in your command window and a note that all the tests were successful. + +Notes about the MPF-MC tests: + +* These tests create a window on the screen and then just re-use the same window for all tests (to save time). So don’t worry if it looks like the window content is scaled weird or blurry or doesn’t fill the entire window. +* Many of these tests are used to test internal workings of the media controller itself, so there will be lots of time when the pop up window is blank or appears frozen since the tests are testing non-visual things. +* The animation and transition tests include testing functionality to stop, restart, pause, and skip frames. So if things look “jerky” in the tests, don’t worry, that doesn’t mean your computer is slow, it’s just how the tests work! :) + diff --git a/docs/code/Writing_Tests/WritingCustomTestsForYourMachine.md b/docs/code/Writing_Tests/WritingCustomTestsForYourMachine.md new file mode 100644 index 0000000000..4cfe95b3ca --- /dev/null +++ b/docs/code/Writing_Tests/WritingCustomTestsForYourMachine.md @@ -0,0 +1,129 @@ + +# Writing Custom Tests for your Machine + +As we already mentioned, the creators of MPF are HUGE believers in the value of automated testing. To that end, MPF includes everything you need to write automated tests that test the logical functionality of your machine. These tests are extremely valuable even if your game is just based on config files. + +For example, you can write a test that simulates starting a game, launching a ball, hitting a sequence of switches, and then verifying that a certain mode is running, or a light is the right color, or an achievement group is in the proper state, etc. Then you can advance the time to timeout a mode and verify that the mode as stopped, etc, etc. + +When you first start building your MPF config, you might think, “What’s the point?”… especially with some of the more simple tests. However your MPF config files will get complex pretty quickly, and often times you’ll think you have some mode done and working perfectly, but then a month later you change something that seems unrelated which ends up breaking it. Unfortunately this usually happens without you knowing it, and by the time you realize that something broke, more times has passed and it’s hard to figure out what broke what. + +So this is where unit tests come in! :) + +If you write simple unit tests that test each new thing you add to an MPF config file, then over time you’ll end up with a huge library of tests for your game. If you get in the habit of running your tests often, then you’ll know right away if a change that you made broke something. (And you’ll also know when everything is ok when all your tests pass again!) + +Tutorial for writing your own tests + +We have a complete tutorial which walks you through writing tests for your own machine. This tutorial conveniently follows the general MPF tutorial at docs.missionpinball.org. Each step here matches the step with the same number there. (Just make sure you’ll looking at the same version of the documentation in both places.) + +In the general MPF tutorial, each step builds on the previous to add more features to the config files for the tutorial project. In the unit test tutorial (what you’re reading here), each step shows you how to write the unit tests which test the new features you just added to the tutorial machine. + +You can follow along and learn here: + +## Step by Step Tutorial + +At this point of time you should have MPF already installed and have some basic game setup. + +### 1. Create a “tests” folder in your machine folder + +First, create a folder called tests in your machine folder. This would be alongside the other folders in there, which will be “config” (created in the MPF tutorial), as well as “logs” and “data” which were created automatically by MPF the first time it ran. + +### 2. Add an empty `__init__.py` file + +Next, inside your new tests folder, create a blank file called `__init__.py`. (That’s two underscores, then the word “init”, then two more underscores, then “.py”.) This file should be totally blank. (It just needs to exist.) This file is needed to let the Python test runner find and load the tests from this folder. + +### 3. Add a test file + +Next you need to add a Python file which actually holds your tests. You can name this file whatever you want as long as it starts with “test”. (The reason for starting it with “test” is also so that the Python test runner knows that this file contains tests, allowing it to automatically find and run tests from it.) + +For now let’s call it test_step_2.py. + +Open that file and add the following lines to it: (If you are interested in what all this means, then read on below the file. Otherwise you can skip down to Step 4.) + +So what’s this file actually doing? + +The import line just imports the base class we use for MPF machine tests. (More details on that is covered in the Testing Class API page). + +Our specific class name TestTutorialMachine can be whatever you want. Again just make sure it starts with “Test” in order for the test runner to find out. + +Our specific method is called test_step_2_mpf_startup(). (Also it has to start with “test”). When the tests are run each method represents a separate “run” of MPF. The test runner will start up MPF and get it all up and running, and then it will move through the code in the test method, then it will cleanly shut down MPF when it’s done. If there are multiple test methods, then the test running will start and stop MPF multiple times. The key is that each test method is run against a “fresh” MPF copy. + +These test methods will also load the machine config files (just like if the command mpf was run the regular way). + +Anyway, in our test method, we have the only actual line that does anything: + +``` +self.assertModeRunning('attract') +``` + +This just tests (“asserts”) that a mode called “attract” is running. There are all sorts of MPF-specific assertion methods which we’ll cover in later steps of this tutorial. + +### 4. Run your test + +You can run your tests via the command prompt from your machine folder. (In other words, the same place where you run mpf to run your machine.) + +The exact command to run is `python -m unittest`. This should produce output similar to the following: + +``` +C:\pinball\your_machine>python -m unittest +C:\Python34\lib\imp.py:32: PendingDeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses + PendingDeprecationWarning) +. +---------------------------------------------------------------------- +Ran 1 test in 0.734s + +OK + +C:\pinball\your_machine> +``` + +That warning about the deprecation can be ignored (if you even have it.. you might not). The important thing is the message towards the bottom: “Ran 1 test in 0.734s” and the “OK” below it. That means your test passed! + +### 5. Check out a failed test + +When you’re writing unit tests, you’ll end up dealing with failed tests a lot! So let’s purposefully change the test so it fails. In this case, change the line which asserts a mode called “attract” is running to look for a mode called “foo” instead, like this: + +``` +self.assertModeRunning('foo') +``` + +Save the file and rerun the tests and you should see results like this: + +``` +C:\pinball\your_machine>python -m unittest +C:\Python34\lib\imp.py:32: PendingDeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses + PendingDeprecationWarning) +F +====================================================================== +FAIL: test_mpf_starts (tests.test_step_2.TestTutorialMachine) +Tests Step 2 of the tutorial +---------------------------------------------------------------------- +Traceback (most recent call last): + File "C:\pinball\your_machine\tests\test_step_2.py", line 18, in test_mpf_starts + self.assertModeRunning('foo') + File "C:\Python34\lib\site-packages\mpf\tests\MpfTestCase.py", line 576, in assertModeRunning + raise AssertionError("Mode {} not known.".format(mode_name)) +AssertionError: Mode foo not known. + +---------------------------------------------------------------------- +Ran 1 test in 0.594s + +FAILED (failures=1) + +C:\pinball\your_machine> +``` + +Note that we see the test run failed, with one failure, and that we can scroll up and see the specific name of the test that failed along with the line that failed, and information about the failure. (In this case it tells us that the mode “foo” is not known.) + +So to get this test to work, you either need to change your MPF config to start a mode called “foo”, or you need to change the test back to looking for a mode called “attract”. :) + +### What if it didn’t work? + +If the unit tests don’t work for you, there are a few things you can try. + +If you get some kind of loading error or config error, make sure you’re running python -m unittest from your machine folder (not from the “tests” folder). + +If you get a message about 0 tests run, make sure you have that empty __init__.py in your tests folder. + +And if you get some weird error that you can’t figure out, then post a message to the MPF Google Group. + + diff --git a/docs/code/Writing_Tests/index.md b/docs/code/Writing_Tests/index.md new file mode 100644 index 0000000000..8afb650026 --- /dev/null +++ b/docs/code/Writing_Tests/index.md @@ -0,0 +1,13 @@ + +# Automated Testing + +The MPF dev team are strong believers in automated testing, and we use a test-driven development (TDD) process for developing MPF itself. (At the time of this writing, there are over 800 unit tests for MPF and MPF-MC, each which contain dozens of individual tests.) + +We have extended Python’s built-in unittest TestCase class for MPF-specific tests, including mocking critical internal elements and adding assertion methods for MPF features. + +You can run built-in tests to test MPF itself or extend them if you think you found a bug or if you’re adding features to MPF. We have also built TestCase classes you can use to write unittests for your own machine. Read on for details: + +* [How to run MPF unittests](RunUnitTests.md) +* [Writing Custom Tests for your Machine](WritingCustomTestsForYourMachine.md) + + diff --git a/docs/code/api_reference/api_reference_config_players.md b/docs/code/api_reference/api_reference_config_players.md new file mode 100644 index 0000000000..aefd2c7b15 --- /dev/null +++ b/docs/code/api_reference/api_reference_config_players.md @@ -0,0 +1,20 @@ + +# Config Players + +Config players are available as machine attributes in the form of their player name plus _player, for example, self.machine.light_player or self.machine.score_player. + +* [blocking_player](config_players/blocking_player.md) +* [coil_player](config_players/coil_player.md) +* [event_player](config_players/event_player.md) +* [flasher_player](config_players/flasher_player.md) +* [hardware_sound_player](config_players/hardware_sound_player.md) +* [light_player](config_players/light_player.md) +* [queue_event_player](config_players/queue_event_player.md) +* [queue_relay_player](config_players/queue_relay_player.md) +* [random_event_player](config_players/random_event_player.md) +* [score_queue_player](config_players/score_queue_player.md) +* [segment_display_player](config_players/segment_display_player.md) +* [show_player](config_players/show_player.md) +* [variable_player](config_players/variable_player.md) + + diff --git a/docs/code/api_reference/api_reference_core.md b/docs/code/api_reference/api_reference_core.md new file mode 100644 index 0000000000..70abfcf7d4 --- /dev/null +++ b/docs/code/api_reference/api_reference_core.md @@ -0,0 +1,23 @@ +# Core Components + +Core MPF machine components, accessible to programmers at self.machine.*name*. For example, the ball controller is at self.machine.ball_controller, the event manager is self.machine.events, etc. + +* [auditor](core/auditor.md) +* [ball_controller](core/ball_controller.md) +* [bcp](core/bcp.md) +* [device_manager](core/device_manager.md) +* [events](core/events.md) +* [info_lights](core/info_lights.md) +* [light_controller](core/light_controller.md) +* [machine](core/machine.md) +* [mode_controller](core/mode_controller.md) +* [placeholder_manager](core/placeholder_manager.md) +* [platform_controller](core/platform_controller.md) +* [service](core/service.md) +* [settings](core/settings.md) +* [show_controller](core/show_controller.md) +* [switch_controller](core/switch_controller.md) +* [switch_player](core/switch_player.md) +* [text_ui](core/text_ui.md) +* [twitch_bot](core/twitch_bot.md) + diff --git a/docs/code/api_reference/api_reference_device.md b/docs/code/api_reference/api_reference_device.md new file mode 100644 index 0000000000..33c1d90600 --- /dev/null +++ b/docs/code/api_reference/api_reference_device.md @@ -0,0 +1,65 @@ + +# Devices + +Instances of MPF devices, available at self.machine.*device_collection*.*device_name*. For example, a flipper device called “right_flipper” is at self.machine.flippers.right_flipper, and a multiball called “awesome” is accessible at self.machine.multiballs.awesome. + +Note that device collections are accessible as attributes and items, so the right flipper mentioned above is also available to programmers at self.machine.flippers['right_flipper']. + +Note + +“Devices” in MPF are more than physical hardware devices. Many of the “game logic” components listed in the user documentation (achievements, ball holds, extra balls, etc.) are implemented as “devices” in MPF code. (So you can think of devices as being either physical or logical.) + +Here’s a list of all the device types in MPF, linked to their API references. + +* [accelerometers](devices/accelerometers.md) +* [accruals](devices/accruals.md) +* [achievement_groups](devices/achievement_groups.md) +* [achievements](devices/achievements.md) +* [autofires](devices/autofires.md) +* [ball_devices](devices/ball_devices.md) +* [ball_holds](devices/ball_holds.md) +* [ball_routings](devices/ball_routings.md) +* [ball_saves](devices/ball_saves.md) +* [coils](devices/coils.md) +* [combo_switches](devices/combo_switches.md) +* [counters](devices/counters.md) +* [digital_outputs](devices/digital_outputs.md) +* [diverters](devices/diverters.md) +* [dmds](devices/dmds.md) +* [drop_target_banks](devices/drop_target_banks.md) +* [drop_targets](devices/drop_targets.md) +* [dual_wound_coils](devices/dual_wound_coils.md) +* [extra_ball_groups](devices/extra_ball_groups.md) +* [extra_balls](devices/extra_balls.md) +* [flippers](devices/flippers.md) +* [hardware_sound_systems](devices/hardware_sound_systems.md) +* [kickbacks](devices/kickbacks.md) +* [light_rings](devices/light_rings.md) +* [light_stripes](devices/light_stripes.md) +* [lights](devices/lights.md) +* [magnets](devices/magnets.md) +* [motors](devices/motors.md) +* [multiball_locks](devices/multiball_locks.md) +* [multiballs](devices/multiballs.md) +* [playfield_transfers](devices/playfield_transfers.md) +* [playfields](devices/playfields.md) +* [psus](devices/psus.md) +* [rgb_dmds](devices/rgb_dmds.md) +* [score_queues](devices/score_queues.md) +* [score_reel_groups](devices/score_reel_groups.md) +* [score_reels](devices/score_reels.md) +* [segment_displays](devices/segment_displays.md) +* [sequence_shots](devices/sequence_shots.md) +* [sequences](devices/sequences.md) +* [servos](devices/servos.md) +* [shot_groups](devices/shot_groups.md) +* [shot_profiles](devices/shot_profiles.md) +* [shots](devices/shots.md) +* [show_queues](devices/show_queues.md) +* [state_machines](devices/state_machines.md) +* [steppers](devices/steppers.md) +* [switches](devices/switches.md) +* [timed_switches](devices/timed_switches.md) +* [timers](devices/timers.md) + + diff --git a/docs/code/api_reference/api_reference_hardware_platforms.md b/docs/code/api_reference/api_reference_hardware_platforms.md new file mode 100644 index 0000000000..e120982d18 --- /dev/null +++ b/docs/code/api_reference/api_reference_hardware_platforms.md @@ -0,0 +1,37 @@ + +# Hardware Platforms + +Hardware platforms are stored in a machine hardware_platforms dictionary, for example, self.machine.hardware_platforms['fast'] or self.machine.hardware_platforms['p_roc']. + +* [drivers](hardware_platforms/drivers.md) +* [fadecandy](hardware_platforms/fadecandy.md) +* [fast](hardware_platforms/fast.md) +* [i2c_servo_controller](hardware_platforms/i2c_servo_controller.md) +* [light_segment_displays](hardware_platforms/light_segment_displays.md) +* [lisy](hardware_platforms/lisy.md) +* [mma8451](hardware_platforms/mma8451.md) +* [mypinballs](hardware_platforms/mypinballs.md) +* [openpixel](hardware_platforms/openpixel.md) +* [opp](hardware_platforms/opp.md) +* [osc](hardware_platforms/osc.md) +* [p3_roc](hardware_platforms/p3_roc.md) +* [p_roc](hardware_platforms/p_roc.md) +* [pin2dmd](hardware_platforms/pin2dmd.md) +* [pololu_maestro](hardware_platforms/pololu_maestro.md) +* [pololu_tic](hardware_platforms/pololu_tic.md) +* [rpi](hardware_platforms/rpi.md) +* [rpi_dmd](hardware_platforms/rpi_dmd.md) +* [smart_virtual](hardware_platforms/smart_virtual.md) +* [smartmatrix](hardware_platforms/smartmatrix.md) +* [smbus2](hardware_platforms/smbus2.md) +* [snux](hardware_platforms/snux.md) +* [spi_bit_bang](hardware_platforms/spi_bit_bang.md) +* [spike](hardware_platforms/spike.md) +* [step_stick](hardware_platforms/step_stick.md) +* [system11](hardware_platforms/system11.md) +* [trinamics_steprocker](hardware_platforms/trinamics_steprocker.md) +* [virtual](hardware_platforms/virtual.md) +* [virtual_pinball](hardware_platforms/virtual_pinball.md) +* [visual_pinball_evolution](hardware_platforms/visual_pinball_evolution.md) + + diff --git a/docs/code/api_reference/api_reference_misc_components.md b/docs/code/api_reference/api_reference_misc_components.md new file mode 100644 index 0000000000..73dc7eb981 --- /dev/null +++ b/docs/code/api_reference/api_reference_misc_components.md @@ -0,0 +1,18 @@ + +# Miscellaneous Components + +There are several other components and systems of MPF that don’t fit into any of the other categories. Those are covered here. + +* [Ball Search](misc_components/BallSearch.md) +* [File Manager](misc_components/FileManager.md) +* [LogMixin](misc_components/LogMixin.md) +* [Mode base class](misc_components/ModeBaseClass.md) +* [Players](misc_components/Players.md) +* [RGBAColor](misc_components/RGBAColor.md) +* [RGBColor](misc_components/RGBColor.md) +* [Randomizer](misc_components/Randomizer.md) +* [Timers](misc_components/Timers.md) +* [Utility Functions](misc_components/UtilityFunctions.md) +* [data_manager](misc_components/DataManager.md) +* [delay_manager](misc_components/DelayManager.md) +* [delay_manager_registry](misc_components/DelayManagerRegistry.md) diff --git a/docs/code/api_reference/api_reference_modes.md b/docs/code/api_reference/api_reference_modes.md new file mode 100644 index 0000000000..acd56ee110 --- /dev/null +++ b/docs/code/api_reference/api_reference_modes.md @@ -0,0 +1,14 @@ + +# Modes + +Covers all the “built-in” modes. They’re accessible via self.machine.modes.*name*, for example, self.machine.modes.game or self.machine.modes.base. + +* [attract](modes/attract.md) +* [bonus](modes/bonus.md) +* [carousel](modes/carousel.md) +* [credits](modes/credits.md) +* [game](modes/game.md) +* [high_score](modes/high_score.md) +* [match](modes/match.md) +* [service](modes/service.md) +* [tilt](modes/tilt.md) diff --git a/docs/code/api_reference/api_reference_testing_class_api.md b/docs/code/api_reference/api_reference_testing_class_api.md new file mode 100644 index 0000000000..2d90f4871a --- /dev/null +++ b/docs/code/api_reference/api_reference_testing_class_api.md @@ -0,0 +1,25 @@ + +# Testing Class API + +MPF includes several unit test classes which you can use to write tests which test MPF or to write tests for your own game. + +These tests include several MPF-specific assertion methods for things like modes, players, balls, device states, etc., as well as logic which advances the time and mocks the BCP and hardware connections. + +You can add commands in your tests to “advance” the time which the MPF tests can test quickly, so you can test a complete 3-minute game play session in a few hundred milliseconds of real world time. + +It might be helpful to look at the real internal tests that MPF uses (which all use these test classes) to get a feel for how tests are written in MPF. They’re available in the mpf/tests folder in the MPF repository. (They’re installed locally when you install MPF.) + +Here’s a diagram which shows how all the MPF and MPF-MC test case classes relate to each other: + +![Testing Classes](testing_class_api/test_classes.png) + +And the API reference for each: + +* [MockBcpClient](testing_class_api/MockBcpClient.md) +* [MpfBcpTestCase](testing_class_api/MpfBcpTestCase.md) +* [MpfFakeGameTestCase](testing_class_api/MpfFakeGameTestCase.md) +* [MpfGameTestCase](testing_class_api/MpfGameTestCase.md) +* [MpfMachineTestCase](testing_class_api/MpfMachineTestCase.md) +* [MpfTestCase](testing_class_api/MpfTestCase.md) +* [TestDataManager](testing_class_api/TestDataManager.md) +* [TestMachineController](testing_class_api/TestMachineController.md) diff --git a/docs/code/api_reference/config_players/blocking_player.md b/docs/code/api_reference/config_players/blocking_player.md new file mode 100644 index 0000000000..df9502b37a --- /dev/null +++ b/docs/code/api_reference/config_players/blocking_player.md @@ -0,0 +1,29 @@ + +# self.machine.blocking_player + +`class mpf.config_players.block_event_player.BlockEventPlayer(machine)` + +Bases: mpf.core.config_player.ConfigPlayer + +Posts events based on config. + +## Accessing the blocking_player in code + +The blocking_player is available via `self.machine.blocking_player`. + +## Methods & Attributes + +The blocking_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value)` + +Parse short config. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Block event. + +`validate_config_entry(settings: dict, name: str) → dict` + +Validate one entry of this player. + diff --git a/docs/code/api_reference/config_players/coil_player.md b/docs/code/api_reference/config_players/coil_player.md new file mode 100644 index 0000000000..f6b2b3ffea --- /dev/null +++ b/docs/code/api_reference/config_players/coil_player.md @@ -0,0 +1,29 @@ + +# self.machine.coil_player + +`class mpf.config_players.coil_player.CoilPlayer(machine)` + +Bases: mpf.config_players.device_config_player.DeviceConfigPlayer + +Triggers coils based on config. + +### Accessing the coil_player in code + +The coil_player is available via `self.machine.coil_player`. + +## Methods & Attributes + +The coil_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +` clear_context(context)` + +Disable enabled coils. + +` get_express_config(value: str)` + +Parse short config version. + +` play(settings, context: str, calling_context: str, priority: int = 0, **kwargs)` + +Enable, Pulse or disable coils. + diff --git a/docs/code/api_reference/config_players/event_player.md b/docs/code/api_reference/config_players/event_player.md new file mode 100644 index 0000000000..aaa13e93e6 --- /dev/null +++ b/docs/code/api_reference/config_players/event_player.md @@ -0,0 +1,29 @@ + +# self.machine.event_player + +`class mpf.config_players.event_player.EventPlayer(machine)` + +Bases: mpf.config_players.flat_config_player.FlatConfigPlayer + +Posts events based on config. + +## Accessing the event_player in code + +The event_player is available via `self.machine.event_player`. + +## Methods & Attributes + +The event_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value)` + +Parse short config. + +`get_list_config(value)` + +Parse list. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Post (delayed) events. + diff --git a/docs/code/api_reference/config_players/flasher_player.md b/docs/code/api_reference/config_players/flasher_player.md new file mode 100644 index 0000000000..3f91003310 --- /dev/null +++ b/docs/code/api_reference/config_players/flasher_player.md @@ -0,0 +1,25 @@ + +# self.machine.flasher_player + +`class mpf.config_players.flasher_player.FlasherPlayer(machine)` + +Bases: mpf.config_players.device_config_player.DeviceConfigPlayer + +Triggers flashers based on config. + +## Accessing the flasher_player in code + +The flasher_player is available via `self.machine.flasher_player`. + +## Methods & Attributes + +The flasher_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value)` + +Parse express config. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Flash flashers. + diff --git a/docs/code/api_reference/config_players/hardware_sound_player.md b/docs/code/api_reference/config_players/hardware_sound_player.md new file mode 100644 index 0000000000..ad10dcf4c4 --- /dev/null +++ b/docs/code/api_reference/config_players/hardware_sound_player.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_sound_player + +`class mpf.config_players.hardware_sound_player.HardwareSoundPlayer(machine)` + +Bases: `mpf.config_players.device_config_player.DeviceConfigPlayer` + +Plays sounds on an external sound card. + +## Accessing the hardware_sound_player_player in code + +The hardware_sound_player_player is available via `self.machine.hardware_sound_player`. + +## Methods & Attributes + +The hardware_sound_player_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value)` + +Parse express config. + +`get_string_config(string)` + +Parse string config. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Play sound on external card. + diff --git a/docs/code/api_reference/config_players/light_player.md b/docs/code/api_reference/config_players/light_player.md new file mode 100644 index 0000000000..b38d5c65f0 --- /dev/null +++ b/docs/code/api_reference/config_players/light_player.md @@ -0,0 +1,33 @@ + +# self.machine.light_player + +`class mpf.config_players.light_player.LightPlayer(machine)` + +Bases: mpf.config_players.device_config_player.DeviceConfigPlayer + +Sets lights based on config. + +## Accessing the light_player in code + +The light_player is available via self.machine.light_player. + +## Methods & Attributes + +The light_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`clear_context(context)` + +Remove all colors which were set in context. + +`get_express_config(value)` + +Parse express config. + +`handle_subscription_change(value, settings, priority, context, key)` + +Handle subscriptions. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Set light color based on config. + diff --git a/docs/code/api_reference/config_players/queue_event_player.md b/docs/code/api_reference/config_players/queue_event_player.md new file mode 100644 index 0000000000..b8fe26ab2f --- /dev/null +++ b/docs/code/api_reference/config_players/queue_event_player.md @@ -0,0 +1,29 @@ + +# self.machine.queue_event_player + +`class mpf.config_players.queue_event_player.QueueEventPlayer(machine)` + +Bases: mpf.core.config_player.ConfigPlayer + +Posts queue events based on config. + +## Accessing the queue_event_player in code + +The queue_event_player is available via `self.machine.queue_event_player`. + +## Methods & Attributes + +The queue_event_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value)` + +No express config. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Post queue events. + +`validate_config_entry(settings, name)` + +Validate one entry of this player. + diff --git a/docs/code/api_reference/config_players/queue_relay_player.md b/docs/code/api_reference/config_players/queue_relay_player.md new file mode 100644 index 0000000000..f643464363 --- /dev/null +++ b/docs/code/api_reference/config_players/queue_relay_player.md @@ -0,0 +1,33 @@ + +# self.machine.queue_relay_player + +`class mpf.config_players.queue_relay_player.QueueRelayPlayer(machine)` + +Bases: mpf.core.config_player.ConfigPlayer + +Blocks queue events and converts them to normal events. + +## Accessing the queue_relay_player in code + +The queue_relay_player is available via `self.machine.queue_relay_player`. + +## Methods & Attributes + +The queue_relay_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`clear_context(context)` + +Clear all queues and remove handlers. + +`get_express_config(value)` + +No express config. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Block queue event. + +`validate_config_entry(settings, name)` + +Validate one entry of this player. + diff --git a/docs/code/api_reference/config_players/random_event_player.md b/docs/code/api_reference/config_players/random_event_player.md new file mode 100644 index 0000000000..d733007059 --- /dev/null +++ b/docs/code/api_reference/config_players/random_event_player.md @@ -0,0 +1,37 @@ + +# self.machine.random_event_player + +`class mpf.config_players.random_event_player.RandomEventPlayer(machine)` + +Bases: mpf.core.config_player.ConfigPlayer + +Plays a random event based on config. + +## Accessing the random_event_player in code + +The random_event_player is available via `self.machine.random_event_player`. + +## Methods & Attributes + +The random_event_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value)` + +Parse express config. + +`get_list_config(value)` + +Parse list. + +`static is_entry_valid_outside_mode(settings) → bool` + +Return true if scope is not player. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Play a random event from list based on config. + +`validate_config_entry(settings, name)` + +Validate one entry of this player. + diff --git a/docs/code/api_reference/config_players/score_queue_player.md b/docs/code/api_reference/config_players/score_queue_player.md new file mode 100644 index 0000000000..8a5e93cf85 --- /dev/null +++ b/docs/code/api_reference/config_players/score_queue_player.md @@ -0,0 +1,33 @@ + +# self.machine.score_queue_player + +`class mpf.config_players.score_queue_player.ScoreQueuePlayer(machine)` + +Bases: `mpf.core.config_player.ConfigPlayer` + +SS style scoring based on config. + +## Accessing the score_queue_player_player in code + +The score_queue_player_player is available via `self.machine.score_queue_player`. + +## Methods & Attributes + +The score_queue_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_express_config(value: Any) → dict` + +Parse express config. + +`static is_entry_valid_outside_mode(settings) → bool` + +Score queue is only valid in game. + +`play(settings: dict, context: str, calling_context: str, priority: int = 0, **kwargs) → None` + +Variable name. + +`validate_config_entry(settings: dict, name: str) → dict` + +Validate one entry of this player. + diff --git a/docs/code/api_reference/config_players/segment_display_player.md b/docs/code/api_reference/config_players/segment_display_player.md new file mode 100644 index 0000000000..61ce986388 --- /dev/null +++ b/docs/code/api_reference/config_players/segment_display_player.md @@ -0,0 +1,29 @@ + +# self.machine.segment_display_player + +`class mpf.config_players.segment_display_player.SegmentDisplayPlayer(machine)` + +Bases: `mpf.config_players.device_config_player.DeviceConfigPlayer` + +Generates texts on segment displays. + +## Accessing the segment_display_player in code + +The segment_display_player_player is available via `self.machine.segment_display_player`. + +## Methods & Attributes + +The segment_display_player_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`clear_context(context)` + +Remove all texts. + +`get_express_config(value)` + +Parse express config. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Show text on display. + diff --git a/docs/code/api_reference/config_players/show_player.md b/docs/code/api_reference/config_players/show_player.md new file mode 100644 index 0000000000..14c623e72f --- /dev/null +++ b/docs/code/api_reference/config_players/show_player.md @@ -0,0 +1,33 @@ + +# self.machine.show_player + +`class mpf.config_players.show_player.ShowPlayer(machine)` + +Bases: mpf.config_players.device_config_player.DeviceConfigPlayer + +Plays, starts, stops, pauses, resumes or advances shows based on config. + +## Accessing the show_player in code + +The show_player is available via `self.machine.show_player`. + +## Methods & Attributes + +The show_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`clear_context(context)` + +Stop running shows from context. + +`get_express_config(value)` + +Parse express config. + +`handle_subscription_change(value, settings, priority, context, key)` + +Handle subscriptions. + +`play(settings, context, calling_context, priority=0, **kwargs)` + +Play, start, stop, pause, resume or advance show based on config. + diff --git a/docs/code/api_reference/config_players/variable_player.md b/docs/code/api_reference/config_players/variable_player.md new file mode 100644 index 0000000000..21a09d863d --- /dev/null +++ b/docs/code/api_reference/config_players/variable_player.md @@ -0,0 +1,45 @@ + +# self.machine.variable_player + +`class mpf.config_players.variable_player.VariablePlayer(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.config_player.ConfigPlayer + +Posts events based on config. + +## Accessing the variable_player in code + +The variable_player is available via `self.machine.variable_player`. + +## Methods & Attributes + +The variable_player has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`clear_context(context: str) → None` + +Clear context. + +`get_express_config(value: Any) → dict` + +Parse express config. + +`get_list_config(value: Any)` + +Parse list. + +`handle_subscription_change(value, settings, priority, context, key)` + +Handle subscriptions. + +`static is_entry_valid_outside_mode(settings: dict) → bool` + +Return true if this entry may run without a game and player. + +`play(settings: dict, context: str, calling_context: str, priority: int = 0, **kwargs) → None` + +Variable name. + +`validate_config_entry(settings: dict, name: str) → dict` + +Validate one entry of this player. + diff --git a/docs/code/api_reference/core/auditor.md b/docs/code/api_reference/core/auditor.md new file mode 100644 index 0000000000..0255b98680 --- /dev/null +++ b/docs/code/api_reference/core/auditor.md @@ -0,0 +1,66 @@ + +# self.machine.auditor + +`class mpf.plugins.auditor.Auditor(machine: MachineController)` + +Bases: object + +Writes switch events, regular events, and player variables to an audit log file. + +## Accessing the auditor in code +There is only one instance of the auditor in MPF, and it’s accessible via self.machine.auditor. + +## Methods & Attributes + +The auditor has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`audit(audit_class, event, **kwargs)` + +Log an auditable event. +Parameters: + +* **audit_class** – A string of the section we want this event to be logged to. +* **event** – A string name of the event we’re auditing. +* ****kwargs** – Not used, but included since some of the audit events might include random kwargs. + +`audit_event(eventname, **kwargs)` + +Record this event in the audit log. +Parameters: + +* **eventname** – The string name of the event. +* ****kwargs** – not used, but included since some types of events include kwargs. + +`audit_player(**kwargs)` + +Write player data to the audit log. Typically this is only called at the end of a game. + +Parameters: +* ****kwargs** – not used, but included since some types of events include kwargs. + +`audit_shot(name, profile, state)` + +Record shot hit. + +`audit_switch(change: mpf.core.switch_controller.MonitoredSwitchChange)` + +Record switch change. + +`disable(**kwargs)` + +Disable the auditor. + +`enable(**kwargs)` + +Enable the auditor. + +This method lets you enable the auditor so it only records things when you want it to. Typically this is called at the beginning of a game. + +Parameters: + +* ****kwargs** – No function here. They just exist to allow this method to be registered as a handler for events that might contain keyword arguments. + +`enabled` + +Attribute that’s viewed by other core components to let them know they should send auditing events. Set this via the enable() and disable() methods. + diff --git a/docs/code/api_reference/core/ball_controller.md b/docs/code/api_reference/core/ball_controller.md new file mode 100644 index 0000000000..6eddd3e838 --- /dev/null +++ b/docs/code/api_reference/core/ball_controller.md @@ -0,0 +1,48 @@ + +# self.machine.ball_controller + +`class mpf.core.ball_controller.BallController(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Tracks and manages all the balls in a pinball machine. + +## Accessing the ball_controller in code + + There is only one instance of the ball_controller in MPF, and it’s accessible via self.machine.ball_controller. + +## Methods & Attributes + +The ball_controller has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_captured_ball(source: mpf.devices.ball_device.ball_device.BallDevice) → None` + +Inform ball controller about a capured ball (which might be new). + +`are_balls_collected(target: Union[str, Iterable[str]]) → bool` + +Check to see if all the balls are contained in devices tagged with the parameter that was passed. +Note if you pass a target that’s not used in any ball devices, this method will return True. (Because you’re asking if all balls are nowhere, and they always are. :) + +Parameters: + +* **target** – String or list of strings of the tags you’d like to collect the balls to. Default of None will be replaced with ‘home’ and ‘trough’. + +`collect_balls(target='home, trough') → None` + +Ensure that all balls are in contained in ball devices with the tag or list of tags you pass. +Typically this would be used after a game ends, or when the machine is reset or first starts up, to ensure that all balls are in devices tagged with ‘home’ and/or ‘trough’. + +Parameters: + +* **target** – A string of the tag name or a list of tags names of the ball devices you want all the balls to end up in. Default is [‘home’, ‘trough’]. + +`dump_ball_counts() → None` + +Dump ball count of all devices. + +`request_to_start_game(**kwargs) → bool` + +Handle result of the request_to_start_game event. +Checks to make sure that the balls are in all the right places and returns. If too many balls are missing (based on the config files ‘Min Balls’ setting), it will return False to reject the game start request. + diff --git a/docs/code/api_reference/core/bcp.md b/docs/code/api_reference/core/bcp.md new file mode 100644 index 0000000000..912e995ac1 --- /dev/null +++ b/docs/code/api_reference/core/bcp.md @@ -0,0 +1,23 @@ +# self.machine.bcp + +`class mpf.core.bcp.bcp.Bcp(machine: MachineController)` + +Bases: `mpf.core.mpf_controller.MpfController` + +BCP Module. + +## Accessing the bcp in code + +There is only one instance of the bcp in MPF, and it’s accessible via self.machine.bcp. + +## Methods & Attributes + +The bcp has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`send(bcp_command, **kwargs)` + +Emulate legacy send. + +Parameters: + +* **bcp_command** – Commmand to send diff --git a/docs/code/api_reference/core/device_manager.md b/docs/code/api_reference/core/device_manager.md new file mode 100644 index 0000000000..091fe7ec9e --- /dev/null +++ b/docs/code/api_reference/core/device_manager.md @@ -0,0 +1,73 @@ + +# self.machine.device_manager + +`class mpf.core.device_manager.DeviceManager(machine)` + +Bases: mpf.core.mpf_controller.MpfController + +Manages all the devices in MPF. + +## Accessing the device_manager in code + +There is only one instance of the device_manager in MPF, and it’s accessible via self.machine.device_manager. + +## Methods & Attributes + +The device_manager has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`create_devices(collection_name, config)` + +Create devices for a collection. + +`create_machinewide_device_control_events(**kwargs)` + +Create machine wide control events. + +`get_device_control_events(config) → Generator[Tuple[str, Callable, int, Device], None, None]` + +Scan a config dictionary for control_events. Yields events, methods, delays, and devices for all the devices and control_events in that config. + + +Parameters: + +* **config** – An MPF config dictionary (either machine-wide or mode- specific). + * The event name + * The callback method of the device + * The delay in ms + * The device object + +`get_monitorable_devices()` + +Return all devices which are registered as monitorable. + +`initialize_devices()` + +Initialise devices. + +`load_devices_config(validate=True)` + +Load all devices. + +`notify_device_changes(device, notify, old, value)` + +Notify subscribers about changes in a registered device. + +Parameters: + +* **device** – The device that changed. +* **notify** – Attribute name which changed. +* **old** – The old value. +* **value** – The new value. + +`register_monitorable_device(device)` + +Register a monitorable device. + +Parameters: + +* **device** – The device to register. + +`stop_devices()` + +Stop all devices in the machine. + diff --git a/docs/code/api_reference/core/events.md b/docs/code/api_reference/core/events.md new file mode 100644 index 0000000000..97f1caa843 --- /dev/null +++ b/docs/code/api_reference/core/events.md @@ -0,0 +1,174 @@ + +# self.machine.events + +`class mpf.core.events.EventManager(machine: MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Handles all the events and manages the handlers in MPF. + +## Accessing the events in code + +There is only one instance of the events in MPF, and it’s accessible via self.machine.events. + +## Methods & Attributes + +The events has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_async_handler(event: str, handler: Any, priority: int = 1, blocking_facility: Any = None, **kwargs) → mpf.core.events.EventHandlerKey` + +Register a coroutine as event handler. + +`add_handler(event: str, handler: Any, priority: int = 1, blocking_facility: Any = None, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler to respond to an event. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The callable method that will be called when the event is fired. Since it’s possible for events to have kwargs attached to them, the handler method must include **kwargs in its signature. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* **blocking_facility** – Facility which can block this event. +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. For example: `my_handler = self.machine.events.add_handler('ev', self.test))` Then later to remove all the handlers that a module added, you could: for handler in handler_list: `events.remove_handler(my_handler)` + +`does_event_exist(event_name: str) → bool` + +Check to see if any handlers are registered for the event name that is passed. + +Parameters: + +* **event_name** – The string name of the event you want to check. + +Returns True or False. + +`get_event_and_condition_from_string` + +Parse an event string to divide the event name from a possible placeholder / conditional in braces. + +Parameters: + +* **event_string** – String to parse +Returns 2-item tuple- First item is the event name. Second item is the condition (A BoolTemplate instance) if it exists, or None if it doesn’t. + +`post(event: str, callback=None, **kwargs) → None` + +Post an event which causes all the registered handlers to be called. Events are processed serially (e.g. one at a time), so if the event core is in the process of handling another event, this event is added to a queue and processed after the current event is done. You can control the order the handlers will be called by optionally specifying a priority when the handlers were registered. (Higher priority values will be processed first.) + +Parameters: + +* **event** – A string name of the event you’re posting. Note that you can post whatever event you want. You don’t have to set up anything ahead of time, and if no handlers are registered for the event you post, so be it. +* **callback** – An optional method which will be called when the final handler is done processing this event. Default is None. +* ****kwargs** – One or more options keyword/value pairs that will be passed to each handler. (The event manager will enforce that handlers have **kwargs in their signatures when they’re registered to prevent run-time crashes from unexpected kwargs that were included in post() calls. + +`post_async(event: str, **kwargs) → _asyncio.Future` + +Post event and wait until all handlers are done. + +`post_boolean(event: str, callback=None, **kwargs) → None` + +Post an boolean event which causes all the registered handlers to be called one-by-one. Boolean events differ from regular events in that if any handler returns False, the remaining handlers will not be called. Events are processed serially (e.g. one at a time), so if the event core is in the process of handling another event, this event is added to a queue and processed after the current event is done. You can control the order the handlers will be called by optionally specifying a priority when the handlers were registered. (Higher priority values will be processed first.) + +Parameters: + +* **event** – A string name of the event you’re posting. Note that you can post whatever event you want. You don’t have to set up anything ahead of time, and if no handlers are registered for the event you post, so be it. +* **callback** – An optional method which will be called when the final handler is done processing this event. Default is None. If any handler returns False and cancels this boolean event, the callback will still be called, but a new kwarg ev_result=False will be passed to it. +* ****kwargs** – One or more options keyword/value pairs that will be passed to each handler. + +`post_queue(event, callback, **kwargs)` + +Post a queue event which causes all the registered handlers to be called. Queue events differ from standard events in that individual handlers are given the option to register a “wait”, and the callback will not be called until any handler(s) that registered a wait will have to release that wait. Once all the handlers release their waits, the callback is called. Events are processed serially (e.g. one at a time), so if the event core is in the process of handling another event, this event is added to a queue and processed after the current event is done. You can control the order the handlers will be called by optionally specifying a priority when the handlers were registered. (Higher numeric values will be processed first.) + +Parameters: + +* **event** - A string name of the event you’re posting. Note that you can post whatever event you want. You don’t have to set up anything ahead of time, and if no handlers are registered for the event you post, so be it. +* **callback** - The method which will be called when the final handler is done processing this event and any handlers that registered waits have cleared their waits. +* ****kwargs** - One or more options keyword/value pairs that will be passed to each handler. (Just make sure your handlers are expecting them. You can add **kwargs to your handler methods if certain ones don’t need them.) + +Post the queue event called `pizza_time`, and then call `self.pizza_done` when done: `self.machine.events.post_queue('pizza_time', self.pizza_done)` + +`post_queue_async(event: str, **kwargs) → _asyncio.Future` + +Post queue event, wait until all handlers are done and locks are released. + +`post_relay(event: str, callback=None, **kwargs) → None` + +Post a relay event which causes all the registered handlers to be called. A dictionary can be passed from handler-to-handler and modified as needed. + +Parameters: + +* **event** – A string name of the event you’re posting. Note that you can post whatever event you want. You don’t have to set up anything ahead of time, and if no handlers are registered for the event you post, so be it. +* **callback** – The method which will be called when the final handler is done processing this event. Default is None. +* ****kwargs** – One or more options keyword/value pairs that will be passed to each handler. (Just make sure your handlers are expecting them. You can add **kwargs to your handler methods if certain ones don’t need them.) + +Events are processed serially (e.g. one at a time), so if the event core is in the process of handling another event, this event is added to a queue and processed after the current event is done. You can control the order the handlers will be called by optionally specifying a priority when the handlers were registered. (Higher priority values will be processed first.) Relay events differ from standard events in that the resulting kwargs from one handler are passed to the next handler. (In other words, standard events mean that all the handlers get the same initial kwargs, whereas relay events “relay” the resulting kwargs from one handler to the next.) + +`post_relay_async(event: str, **kwargs) → _asyncio.Future` + +Post relay event, wait until all handlers are done and return result. + +`process_event_queue() → None` + +Check if there are any other events that need to be processed, and then process them. + +`remove_all_handlers_for_event(event: str) → None` + +Remove all handlers for event. Use carefully. This is currently used to remove handlers for all init events which only occur once. + +`remove_handler(method: Any) → None` + +Remove an event handler from all events a method is registered to handle. + +Parameters: + +* **method** – The method whose handlers you want to remove. + +`remove_handler_by_event(event: str, handler: Any) → None` + +Remove the handler you pass from the event you pass. + +Parameters: + +* **event** – The name of the event you want to remove the handler from. +* **handler** – The handler method you want to remove. + +Note that keyword arguments for the handler are not taken into consideration. In other words, this method only removes the registered handler / event combination, regardless of whether the keyword arguments match or not. + +`remove_handler_by_key(key: mpf.core.events.EventHandlerKey) → None` + +Remove a registered event handler by key. + +Parameters: + +* **key** – The key of the handler you want to remove + +`remove_handlers_by_keys(key_list: List[mpf.core.events.EventHandlerKey]) → None` + +Remove multiple event handlers based on a passed list of keys. + +Parameters: + +* **key_list** – A list of keys of the handlers you want to remove + +`replace_handler(event: str, handler: Any, priority: int = 1, **kwargs) → mpf.core.events.EventHandlerKey` + +Check to see if a handler (optionally with kwargs) is registered for an event and replaces it if so. + +Parameters: + +* **event** – The event you want to check to see if this handler is registered for. +* **handler** – The method of the handler you want to check. +* **priority** – Optional priority of the new handler that will be registered. +* ****kwargs** – The kwargs you want to check and the kwargs that will be registered with the new handler. + +If you don’t pass kwargs, this method will just look for the handler and event combination. If you do pass kwargs, it will make sure they match before replacing the existing entry. If this method doesn’t find a match, it will still add the new handler. + +`wait_for_any_event(event_names: List[str]) → _asyncio.Future` + +Wait for any event from event_names. + +`wait_for_event(event_name: str) → _asyncio.Future` + +Wait for event. + diff --git a/docs/code/api_reference/core/info_lights.md b/docs/code/api_reference/core/info_lights.md new file mode 100644 index 0000000000..880879e403 --- /dev/null +++ b/docs/code/api_reference/core/info_lights.md @@ -0,0 +1,17 @@ + +# self.machine.info_lights + +`class mpf.plugins.info_lights.InfoLights(machine)` + +Bases: object + +Uses lights to represent game state. Info lights are primarily used in EM and early solid state machines, typically lights in the backbox for game over, tilt, which player is up, the current ball number, etc. + +## Accessing the info_lights in code + +There is only one instance of the info_lights in MPF, and it’s accessible via `self.machine.info_lights`. + +## Methods & Attributes + +The `info_lights` has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + diff --git a/docs/code/api_reference/core/light_controller.md b/docs/code/api_reference/core/light_controller.md new file mode 100644 index 0000000000..f9ff0c40c4 --- /dev/null +++ b/docs/code/api_reference/core/light_controller.md @@ -0,0 +1,25 @@ + +# self.machine.light_controller + +`class mpf.core.light_controller.LightController(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Handles light updates and light monitoring. + +## Accessing the light_controller in code + +There is only one instance of the light_controller in MPF, and it’s accessible via `self.machine.light_controller`. + +## Methods & Attributes + +The `light_controller` has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`initialise_light_subsystem()` + +Initialise the light subsystem. + +`monitor_lights()` + +Update the color of lights for the monitor. + diff --git a/docs/code/api_reference/core/machine.md b/docs/code/api_reference/core/machine.md new file mode 100644 index 0000000000..fd1d5ca856 --- /dev/null +++ b/docs/code/api_reference/core/machine.md @@ -0,0 +1,111 @@ + +# self.machine + +`class mpf.core.machine.MachineController(options: dict, config: mpf.core.config_loader.MpfConfig)` + +Bases: mpf.core.logging.LogMixin + + +Parameters: + +* **config (MpfConfig)** – The machine configuration +* **options (dict)** – A dictionary of options built from the command line options used to launch mpf.py. + +## Accessing the machine controller in code + +The machine controller is the main component in MPF, accessible via self.machine. See the Overview & Tour of MPF code for details. + +## Methods & Attributes + +The machine controller has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_crash_handler(handler: Callable)` + +Add a crash handler which is called on a crash. This can be used to restore the output and prepare logging. + +`add_platform(name: str) → None` +Make an additional hardware platform interface available to MPF. + +Parameters: + +* **name** – String name of the platform to add. Must match the name of a platform file in the mpf/platforms folder (without the .py extension). + +`clear_boot_hold(hold: str) → None` + +Clear a boot hold. + +`create_data_manager(config_name: str) → mpf.core.data_manager.DataManager` + +Return a new DataManager for a certain config. + +Parameters: + +* **config_name** – Name of the config + +`get_platform_sections(platform_section: str, overwrite: str) → SmartVirtualHardwarePlatform` + +Return platform section. + +`init_done() → None` + +Finish init. Called when init is done and all boot holds are cleared. + +`initialise() → None` + +Initialise machine. + +`initialise_core_and_hardware() → None` + +Load core modules and hardware. + +`initialise_mpf()` + +Initialise MPF. + +`register_boot_hold(hold: str) → None` + +Register a boot hold. + +`register_monitor(monitor_class: str, monitor: Callable[[...], Any]) → None` + +Register a monitor. + +Parameters: + +* **monitor_class** – String name of the monitor class for this monitor that’s being registered. +* **monitor** – Callback to notify + +MPF uses monitors to allow components to monitor certain internal elements of MPF. For example, a player variable monitor could be setup to be notified of any changes to a player variable, or a switch monitor could be used to allow a plugin to be notified of any changes to any switches. The MachineController’s list of registered monitors doesn’t actually do anything. Rather it’s a dictionary of sets which the monitors themselves can reference when they need to do something. We just needed a central registry of monitors. + +`reset() → None` + +Reset the machine. This method is safe to call. It essentially sets up everything from scratch without reloading the config files and assets from disk. This method is called after a game ends and before attract mode begins. + +`run() → None` + +Start the main machine run loop. + +`set_default_platform(name: str) → None` + +Set the default platform. It is used if a device class-specific or device-specific platform is not specified. + +Parameters: + +* **name** – String name of the platform to set to default. + +`shutdown() → None` + +Shutdown the machine. + +`stop(reason=None, **kwargs) → None` + +Perform a graceful exit of MPF. + +`validate_machine_config_section(section: str) → None` + +Validate a config section. + +`verify_system_info()` + +Dump information about the Python installation to the log. Information includes Python version, Python executable, platform, and core architecture. + diff --git a/docs/code/api_reference/core/mode_controller.md b/docs/code/api_reference/core/mode_controller.md new file mode 100644 index 0000000000..b6c66f7c64 --- /dev/null +++ b/docs/code/api_reference/core/mode_controller.md @@ -0,0 +1,77 @@ + +# self.machine.mode_controller + +`class mpf.core.mode_controller.ModeController(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Responsible for loading, unloading, and managing all modes in MPF. + +## Accessing the mode_controller in code + +There is only one instance of the mode_controller in MPF, and it’s accessible via self.machine.mode_controller. + +## Methods & Attributes + +The mode_controller has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`create_mode_devices()` + +Create mode devices. + +`dump()` + +Dump the current status of the running modes to the log file. + +`initialise_modes(**kwargs)` + +Initialise modes. + +`is_active(mode_name) → bool` + +Return true if the mode is active, False if it is not. + +Parameters: + +* **mode_name** – String name of the mode to check. + +`load_mode_devices()` + +Load mode devices. + +`load_modes(**kwargs)` + +Load the modes from the modes: section of the machine configuration file. + +`register_load_method(load_method, config_section_name=None, priority=0, **kwargs)` + +Register a method which is called when the mode is loaded. Used by core components, plugins, etc. to register themselves with the Mode Controller for anything they need a mode to do when it’s registered. + +Parameters: + +* **load_method** – The method that will be called when this mode code loads. +* **config_section_name** – An optional string for the section of the configuration file that will be passed to the load_method when it’s called. +* **priority** – Int of the relative priority which allows remote methods to be called in a specific order. Default is 0. Higher values will be called first. +* ****kwargs** – Any additional keyword arguments specified will be passed to the load_method. + +Note that these methods will be called once, when the mode code is first initialized during the MPF boot process. + +`register_start_method(start_method, config_section_name=None, priority=0, **kwargs)` + +Register a method which is called anytime a mode is started. Used by core components, plugins, etc. to register themselves with the Mode Controller for anything that they a mode to do when it starts. + +Parameters: + +* **start_method** – The method that will be called when this mode code loads. +* **config_section_name** – An optional string for the section of the configuration file that will be passed to the start_method when it’s called. +* **priority** – Int of the relative priority which allows remote methods to be called in a specific order. Default is 0. Higher values will be called first. +* ****kwargs** – Any additional keyword arguments specified will be passed to the start_method. + +`remove_start_method(start_method, config_section_name=None, priority=0, **kwargs)` + +Remove an existing start method. + +`set_mode_state(mode: mpf.core.mode.Mode, active: bool)` + +Remember mode state. + diff --git a/docs/code/api_reference/core/placeholder_manager.md b/docs/code/api_reference/core/placeholder_manager.md new file mode 100644 index 0000000000..0f18f8aa37 --- /dev/null +++ b/docs/code/api_reference/core/placeholder_manager.md @@ -0,0 +1,21 @@ + +# self.machine.placeholder_manager + +`class mpf.core.placeholder_manager.PlaceholderManager(machine)` + +Bases: mpf.core.placeholder_manager.BasePlaceholderManager + +Manages templates and placeholders for MPF. + +## Accessing the placeholder_manager in code + +There is only one instance of the placeholder_manager in MPF, and it’s accessible via self.machine.placeholder_manager. + +## Methods & Attributes + +The placeholder_manager has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`get_global_parameters(name)` + +Return global params. + diff --git a/docs/code/api_reference/core/platform_controller.md b/docs/code/api_reference/core/platform_controller.md new file mode 100644 index 0000000000..bf98d66d28 --- /dev/null +++ b/docs/code/api_reference/core/platform_controller.md @@ -0,0 +1,90 @@ +# self.machine.platform_controller + +`class mpf.core.platform_controller.PlatformController(machine: MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Manages all platforms and rules. + +## Accessing the platform_controller in code + +There is only one instance of the platform_controller in MPF, and it’s accessible via `self.machine.platform_controller`. + +## Methods & Attributes + +The platform_controller has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(rule: mpf.core.platform_controller.HardwareRule)` + +Clear all rules for switch and this driver. + +Parameters: + +* **rule** – Hardware rule to clean. + +`set_delayed_pulse_on_hit_rule(enable_switch: mpf.core.platform_controller.SwitchRuleSettings, driver: mpf.core.platform_controller.DriverRuleSettings, delay_ms, pulse_setting: mpf.core.platform_controller.PulseRuleSettings = None) → mpf.core.platform_controller.HardwareRule` + +Add delayed pulse on hit rule to driver. Always do the full pulse. Even when the switch is released. Pulse is delayed accurately by the hardware. + +Parameters: + +* **enable_switch** – Switch which triggers the rule. +* **driver** – `class DriverRuleSettings` +* **delay_ms** – Delay before the pulse in ms +* **pulse_setting** – `class PulseRuleSettings` + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform_controller.SwitchRuleSettings, eos_switch: mpf.core.platform_controller.SwitchRuleSettings, driver: mpf.core.platform_controller.DriverRuleSettings, pulse_setting: Optional[mpf.core.platform_controller.PulseRuleSettings] = None, hold_settings: Optional[mpf.core.platform_controller.HoldRuleSettings] = None, eos_settings: Optional[mpf.core.platform_controller.RepulseRuleSettings] = None) → mpf.core.platform_controller.HardwareRule` + +Add pulse on hit and enable and release and disable rule to driver. Pulse and then enable driver. Cancel pulse and enable when switch is released or a disable switch is hit. + +Parameters: + +* **enable_switch** – Switch to enable coil. +* **eos_switch** – Switch to switch from pulse to hold and to trigger repulses. +* **driver** – Driver to enable. +* **pulse_setting** – Pulse settings. +* **hold_settings** – Hold settings. +* **eos_settings** – How to repulse the coil when EOS opens. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform_controller.SwitchRuleSettings, driver: mpf.core.platform_controller.DriverRuleSettings, pulse_setting: mpf.core.platform_controller.PulseRuleSettings = None, hold_settings: mpf.core.platform_controller.HoldRuleSettings = None) → mpf.core.platform_controller.HardwareRule` + +Add pulse on hit and enable and release rule to driver. Pulse and enable a driver. Cancel pulse and enable if switch is released. + +Parameters: + +* **enable_switch** – Switch which triggers the rule. +* **driver** – Driver to trigger. +* **pulse_setting** – `class PulseRuleSettings` +* **hold_settings** – `class HoldRuleSettings` + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform_controller.SwitchRuleSettings, eos_switch: mpf.core.platform_controller.SwitchRuleSettings, driver: mpf.core.platform_controller.DriverRuleSettings, pulse_setting: Optional[mpf.core.platform_controller.PulseRuleSettings] = None, eos_settings: Optional[mpf.core.platform_controller.RepulseRuleSettings] = None) → mpf.core.platform_controller.HardwareRule` + +Add pulse on hit and release and disable rule to driver. Pulse driver. Cancel pulse when switch is released or a disable switch is hit. + +Parameters: + +* **enable_switch** – Switch to enable coil. +* **eos_switch** – Switch to cancel pulse and trigger repulses. +* **driver** – Driver to enable. +* **pulse_setting** – Pulse settings. +* **eos_settings** – How to repulse the coil when EOS opens. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform_controller.SwitchRuleSettings, driver: mpf.core.platform_controller.DriverRuleSettings, pulse_setting: mpf.core.platform_controller.PulseRuleSettings = None) → mpf.core.platform_controller.HardwareRule` + +Add pulse on hit and release rule to driver. Pulse a driver but cancel pulse when switch is released. + +Parameters: + +* **enable_switch** – Switch which triggers the rule. +* **driver** – `class DriverRuleSettings` +* **pulse_setting** – `class PulseRuleSettings` + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform_controller.SwitchRuleSettings, driver: mpf.core.platform_controller.DriverRuleSettings, pulse_setting: mpf.core.platform_controller.PulseRuleSettings = None) → mpf.core.platform_controller.HardwareRule` + +Add pulse on hit rule to driver. Always do the full pulse. Even when the switch is released. + +Parameters: + +* **enable_switch** – Switch which triggers the rule. +* **driver** – `class DriverRuleSettings` +* **pulse_setting** – `class PulseRuleSettings` diff --git a/docs/code/api_reference/core/service.md b/docs/code/api_reference/core/service.md new file mode 100644 index 0000000000..95a7f3c8bc --- /dev/null +++ b/docs/code/api_reference/core/service.md @@ -0,0 +1,45 @@ + +# self.machine.service + +`class mpf.core.service_controller.ServiceController(machine)` + +Bases: mpf.core.mpf_controller.MpfController + +Provides all service information and can perform service tasks. + +## Accessing the service in code + +There is only one instance of the service in MPF, and it’s accessible via `self.machine.service`. + +## Methods & Attributes + +The service has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_technical_alert(device, issue)` + +Add an alert about a technical problem. + +`get_coil_map() → List[mpf.core.service_controller.CoilMap]` + +Return a map of all coils in the machine. + +`get_light_map() → List[mpf.core.service_controller.LightMap]` + +Return a map of all lights in the machine. + +`get_switch_map()` + +Return a map of all switches in the machine. + +`is_in_service() → bool` + +Return true if in service mode. + +`start_service()` + +Start service mode. + +`stop_service()` + +Stop service mode. + diff --git a/docs/code/api_reference/core/settings.md b/docs/code/api_reference/core/settings.md new file mode 100644 index 0000000000..c8ec710995 --- /dev/null +++ b/docs/code/api_reference/core/settings.md @@ -0,0 +1,41 @@ + +# self.machine.settings + +`class mpf.core.settings_controller.SettingsController(machine)` + +Bases: mpf.core.mpf_controller.MpfController + +Manages operator controllable settings. + +## Accessing the settings in code + +There is only one instance of the settings in MPF, and it’s accessible via `self.machine.settings`. + +## Methods & Attributes + +The settings has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_setting(setting: mpf.core.settings_controller.SettingEntry)` + +Add a setting. + +`get_setting_machine_var(setting_name)` + +Return machine var name. + +`get_setting_value(setting_name)` + +Return the current value of a setting. + +`get_setting_value_label(setting_name)` + +Return label for value. + +`get_settings() → List[mpf.core.settings_controller.SettingEntry]` + +Return all available settings. + +`set_setting_value(setting_name, value)` + +Set the value of a setting. + diff --git a/docs/code/api_reference/core/show_controller.md b/docs/code/api_reference/core/show_controller.md new file mode 100644 index 0000000000..efbae14def --- /dev/null +++ b/docs/code/api_reference/core/show_controller.md @@ -0,0 +1,37 @@ + +# self.machine.show_controller + +`class mpf.core.show_controller.ShowController(machine)` + +Bases: mpf.core.mpf_controller.MpfController + +Manages all the shows in a pinball machine. The ShowController handles priorities, restores, running and stopping shows, etc. + +## Accessing the show_controller in code + +There is only one instance of the show_controller in MPF, and it’s accessible via `self.machine.show_controller`. + +## Methods & Attributes + +The show_controller has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`create_show_config(name, priority=0, speed=1.0, loops=-1, sync_ms=None, manual_advance=False, show_tokens=None, events_when_played=None, events_when_stopped=None, events_when_looped=None, events_when_paused=None, events_when_resumed=None, events_when_advanced=None, events_when_stepped_back=None, events_when_updated=None, events_when_completed=None)` + +Create a show config. + +`get_next_show_id()` + +Return the next show id. + +`play_show_with_config(config, mode=None, start_time=None)` + +Play and return a show from config. Will add the mode priority if a mode is passed. + +`register_show(name)` + +Register a named show. + +`replace_or_advance_show(old_instance, config: mpf.assets.show.ShowConfig, start_step, start_time=None, start_running=True, stop_callback=None)` + +Replace or advance show. Compare a given show (may be empty) to a show config and ensure that the new config becomes effective. If the old show runs a config which is equal to the new config nothing will be done. If the old_instance is set to manual_advance and one step behind the target step it will advance the show. Otherwise, the old show is stopped and the new show is stopped in sync. + diff --git a/docs/code/api_reference/core/switch_controller.md b/docs/code/api_reference/core/switch_controller.md new file mode 100644 index 0000000000..0029de88f6 --- /dev/null +++ b/docs/code/api_reference/core/switch_controller.md @@ -0,0 +1,172 @@ +# self.machine.switch_controller + +`class mpf.core.switch_controller.SwitchController(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Tracks all switches in the machine, receives switch activity, and converts switch changes into events. + +## Accessing the switch_controller in code + +There is only one instance of the switch_controller in MPF, and it’s accessible via `self.machine.switch_controller`. + +## Methods & Attributes + +The switch_controller has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_monitor(monitor: Callable[[mpf.core.switch_controller.MonitoredSwitchChange], None])` + +Add a monitor callback which is called on switch changes. + +`add_switch_handler(switch_name, callback, state=1, ms=0, return_info=False, callback_kwargs=None) → mpf.core.switch_controller.SwitchHandler` + +Register a handler to take action on a switch event. + +Parameters: + +* **switch_name** – String name of the switch you’re adding this handler for. +* **callback** – The method you want called when this switch handler fires. +* **state** – Integer of the state transition you want to callback to be triggered on. Default is 1 which means it’s called when the switch goes from inactive to active, but you can also use 0 which means your callback will be called when the switch becomes inactive +* **ms – Integer** - If you specify a ‘ms’ parameter, the handler won’t be called until the witch is in that state for that many milliseconds. +* **return_info** – If True, the switch controller will pass the parameters of the switch handler as arguments to the callback, including switch_name, state, and ms. If False (default), it just calls the callback with no parameters. +* **callback_kwargs** – Additional kwargs that will be passed with the callback. + +You can mix & match entries for the same switch here. + +`add_switch_handler_obj(switch, callback, state=1, ms=0, return_info=False, callback_kwargs=None)` + +Register a handler to take action on a switch event. Same as add_switch_handler but you can pass a switch object instead of a name. + +`static get_active_event_for_switch(switch_name)` + +Return the event name which is posted when switch_name becomes active. + +`is_active(switch, ms=None)` + +Query whether a switch is active. + +Parameters: + +* **switch** – Switch object to check. +* **ms** – Milliseconds that the switch has been active. If this is non-zero, then this method will only return True if the switch has been in that state for at least the number of ms specified. + +Returns: True if the switch_name has been active for the given number of ms. If ms is not specified, returns True if the switch is in the state regardless of how long it’s been in that state. + +`is_inactive(switch, ms=None)` + +Query whether a switch is inactive. + +Parameters: + +* **switch** – Switch object to check. +* **ms** – Milliseconds that the switch has been inactive. If this is non-zero, then this method will only return True if the switch has been in that state for at least the number of ms specified. number of ms. If ms is not specified, returns True if the switch is in the state regardless of how long it’s been in that state. + +`is_state(switch: mpf.devices.switch.Switch, state, ms=0.0)` + +Check if switch is in state. Query whether a switch is in a given state and (optionally) whether it has been in that state for the specified number of ms. + +Parameters: + +* **switch** – Switch object to check. +* **state** – Bool of the state to check. True is active and False is inactive. +* **ms** – Milliseconds that the switch has been in that state. If this is non-zero, then this method will only return True if the switch has been in that state for at least the number of ms specified. + +Returns: True if the switch_name has been in the state for the given number of ms. If ms is not specified, returns True if the switch is in the state regardless of how long it’s been in that state. + +`log_active_switches(**kwargs)` + +Write out entries to the INFO log file of all switches that are currently active. + +`process_switch(name, state, logical=False, timestamp=None)` + +Process a new switch state change for a switch by name. This is the method that is called by the platform driver whenever a switch changes state. It’s also used by the “other” modules that activate switches, including the keyboard and OSC interfaces. State 0 means the switch changed from active to inactive, and 1 means it changed from inactive to active. (The hardware & platform code handles NC versus NO switches and translates them to ‘active’ versus ‘inactive’.) + +Parameters: + +* **name** – The string name of the switch. +* **state** – Boolean or int of state of the switch you’re processing, True/1 is active, False/0 is inactive. +* **logical** – Boolean which specifies whether the ‘state’ argument represents the “physical” or “logical” state of the switch. If True, a 1 means this switch is active and a 0 means it’s inactive, regardless of the NC/NO configuration of the switch. If False, then the state parameter passed will be inverted if the switch is configured to be an ‘NC’ type. Typically the hardware will send switch states in their raw (logical=False) states, but other interfaces like the keyboard and OSC will use logical=True. +* **timestamp** – Timestamp when this switch change happened. + +`process_switch_by_num(num, state, platform, logical=False, timestamp=None)` + +Process a switch state change by switch number. + +Parameters: + +* **num** – The switch number (based on the platform number) for the switch you’re setting. +* **state** – The state to set, either 0 or 1. +* **platform** – The platform this switch is on. +* **logical** – Whether the state you’re setting is the logical or physical state of the switch. If a switch is NO (normally open), then the logical and physical states will be the same. NC (normally closed) switches will have physical and logical states that are inverted from each other. +* **timestamp** – Timestamp when this switch change happened. + +`process_switch_obj(obj: mpf.devices.switch.Switch, state, logical, timestamp=None)` + +Process a new switch state change for a switch by name. + +Parameters: + +* **obj** – The switch object. +* **state** – Boolean or int of state of the switch you’re processing, True/1 is active, False/0 is inactive. +* **logical** – Boolean which specifies whether the ‘state’ argument represents the “physical” or “logical” state of the switch. If True, a 1 means this switch is active and a 0 means it’s inactive, regardless of the NC/NO configuration of the switch. If False, then the state parameter passed will be inverted if the switch is configured to be an ‘NC’ type. Typically the hardware will send switch states in their raw (logical=False) states, but other interfaces like the keyboard and OSC will use logical=True. +* **timestamp** – Timestamp when this switch change happened. + +This is the method that is called by the platform driver whenever a switch changes state. It’s also used by the “other” modules that activate switches, including the keyboard and OSC interfaces. State 0 means the switch changed from active to inactive, and 1 means it changed from inactive to active. (The hardware & platform code handles NC versus NO switches and translates them to ‘active’ versus ‘inactive’.) + +`register_switch(switch: mpf.devices.switch.Switch)` + +Add a switch object to the switch controller for tracking. + +Parameters: + +switch – Switch object to add + +`remove_monitor(monitor: Callable[[mpf.core.switch_controller.MonitoredSwitchChange], None])` + +Remove a monitor callback. + +`remove_switch_handler(switch_name, callback, state=1, ms=0)` + +Remove a registered switch handler. Currently this only works if you specify everything exactly as you set it up. (Except for return_info, which doesn’t matter if true or false, it will remove either / both. + +`remove_switch_handler_by_key(switch_handler: mpf.core.switch_controller.SwitchHandler)` + +Remove switch handler by key returned from `add_switch_handler`. + +`remove_switch_handler_by_keys(switch_handlers: List[mpf.core.switch_controller.SwitchHandler])` + +Remove switch handlers by list of keys returned from `add_switch_handler`. + +`remove_switch_handler_obj(switch, callback, state=1, ms=0)` + +Remove a registered switch handler. Same as remove_switch_handler but takes a switch object instead of the name. + +`update_switches_from_hw()` + +Update the states of all the switches be re-reading the states from the hardware platform. This method works silently and does not post any events if any switches changed state. + +`verify_switches() → bool` + +Verify that switches states match the hardware. Loops through all the switches and queries their hardware states via their platform interfaces and then compares that to the state that MPF thinks the switches are in. Throws logging warnings if anything doesn’t match. This method is notification only. It doesn’t fix anything. + +`wait_for_any_switch(switches: List[mpf.devices.switch.Switch], state: int = 1, only_on_change=True, ms=0)` + +Wait for the first switch in the list to change into state. + +Parameters: + +* **switches** – Iterable of switches. Whichever switch changes first will trigger this wait. +* **state** – The state to wait for. 0 = inactive, 1 = active, 2 = opposite to current. +* **only_on_change** – Bool which controls whether this wait will be triggered now if the switch is already in the state, or whether it will wait until the switch changes into that state. +* **ms** – How long the switch needs to be in the new state to trigger the wait. + +`wait_for_switch(switch: mpf.devices.switch.Switch, state: int = 1, only_on_change=True, ms=0)` + +Wait for a switch to change into a state. + +Parameters: + +* **switch** – String to wait for. +* **state** – The state to wait for. 0 = inactive, 1 = active, 2 = opposite to current. +* **only_on_change** – Bool which controls whether this wait will be triggered now if the switch is already in the state, or whether it will wait until the switch changes into that state. +* **ms** – How long the switch needs to be in the new state to trigger the wait. diff --git a/docs/code/api_reference/core/switch_player.md b/docs/code/api_reference/core/switch_player.md new file mode 100644 index 0000000000..ffc7a7ae7f --- /dev/null +++ b/docs/code/api_reference/core/switch_player.md @@ -0,0 +1,17 @@ + +# self.machine.switch_player + +`class mpf.plugins.switch_player.SwitchPlayer(machine)` + +Bases: object + +Plays back switch sequences from a config file, used for testing. + +## Accessing the switch_player in code + +There is only one instance of the `switch_player` in MPF, and it’s accessible via `self.machine.switch_player`. + +## Methods & Attributes + +The `switch_player` has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + diff --git a/docs/code/api_reference/core/text_ui.md b/docs/code/api_reference/core/text_ui.md new file mode 100644 index 0000000000..315624f3b9 --- /dev/null +++ b/docs/code/api_reference/core/text_ui.md @@ -0,0 +1,21 @@ + +# self.machine.text_ui + +`class mpf.core.text_ui.TextUi(machine: MachineController)` + +Bases: mpf.core.mpf_controller.MpfController + +Handles the text-based UI. + +## Accessing the text_ui in code + +There is only one instance of the `text_ui` in MPF, and it’s accessible via `self.machine.text_ui`. + +## Methods & Attributes + +The text_ui has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`stop(**kwargs)` + +Stop the Text UI and restore the original console screen. + diff --git a/docs/code/api_reference/core/twitch_bot.md b/docs/code/api_reference/core/twitch_bot.md new file mode 100644 index 0000000000..33372e4678 --- /dev/null +++ b/docs/code/api_reference/core/twitch_bot.md @@ -0,0 +1,17 @@ + +# self.machine.twitch_bot + +`class mpf.plugins.twitch_bot.TwitchBot(machine)` + +Bases: mpf.core.logging.LogMixin + +Adds Twitch chat room events. + +## Accessing the twitch_bot in code + +There is only one instance of the `twitch_bot` in MPF, and it’s accessible via `self.machine.twitch_bot`. + +## Methods & Attributes + +The `twitch_bot` has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + diff --git a/docs/code/api_reference/devices/accelerometers.md b/docs/code/api_reference/devices/accelerometers.md new file mode 100644 index 0000000000..850c942627 --- /dev/null +++ b/docs/code/api_reference/devices/accelerometers.md @@ -0,0 +1,49 @@ + +# self.machine.accelerometers.* + +`class mpf.devices.accelerometer.Accelerometer(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Implements a multi-axis accelerometer. In modern machines, accelerometers can be used for tilt detection and to detect whether a machine is properly leveled. The accelerometer device produces a data stream of readings which MPF converts to g-forces, and then events can be posted when the “hit” (or g-force) of an accelerometer exceeds a predefined threshold. + +## Accessing accelerometers in code + +The device collection which contains the accelerometers in your machine is available via self.machine.accelerometers. For example, to access one called “foo”, you would use self.machine.accelerometers.foo. You can also access accelerometers in dictionary form, e.g. `self.machine.accelerometers['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Accelerometers have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_level_xyz() → float` + +Return current 3D level. + +`get_level_xz() → float` + +Return current 2D x/z level. + +`get_level_yz() → float` + +Return current 2D y/z level. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`update_acceleration(x: float, y: float, z: float) → None` + +Calculate acceleration based on readings from hardware. + diff --git a/docs/code/api_reference/devices/accruals.md b/docs/code/api_reference/devices/accruals.md new file mode 100644 index 0000000000..7af9a96a57 --- /dev/null +++ b/docs/code/api_reference/devices/accruals.md @@ -0,0 +1,97 @@ + +# self.machine.accruals.* + +`class mpf.devices.logic_blocks.Accrual(*args, **kwargs)` + +Bases: mpf.devices.logic_blocks.LogicBlock + +A type of LogicBlock which tracks many different events (steps) towards a goal. The steps are able to happen in any order. + +## Accessing accruals in code + +The device collection which contains the accruals in your machine is available via `self.machine.accruals`. For example, to access one called “foo”, you would use `self.machine.accruals.foo`. You can also access accruals in dictionary form, e.g. `self.machine.accruals['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Accruals have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`complete()` + +Mark this logic block as complete. Posts the ‘events_when_complete’ events and optionally restarts this logic block or disables it, depending on this block’s configuration settings. + +`completed` + +Return if completed. + +`disable()` + +Disable this logic block. Automatically called when one of the disable_event events is posted. Can also manually be called. + +`enable()` + +Enable this logic block. Automatically called when one of the enable_event events is posted. Can also manually be called. + +`enabled` + +Return if enabled. + +`event_advance_random(**kwargs)` + +Event handler for advance random events. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`event_restart(**kwargs)` + +Event handler for restart event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`get_start_value() → List[bool]` + +Return start states. + +`hit(step: int, **kwargs)` + +Increase the hit progress towards completion. Automatically called when one of the count_events is posted. Can also manually be called. + +Parameters: + +* **step** – Integer of the step number (0 indexed) that was just hit. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset the progress towards completion of this logic block. Automatically called when one of the reset_event events is called. Can also be manually called. + +`restart()` + +Restart this logic block by calling reset() and enable(). Automatically called when one of the restart_event events is called. Can also be manually called. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`value` + +Return value or None if that is currently not possible. + diff --git a/docs/code/api_reference/devices/achievement_groups.md b/docs/code/api_reference/devices/achievement_groups.md new file mode 100644 index 0000000000..f807599a8c --- /dev/null +++ b/docs/code/api_reference/devices/achievement_groups.md @@ -0,0 +1,89 @@ + +# self.machine.achievement_groups.* + +`class mpf.devices.achievement_group.AchievementGroup(*args, **kwargs)` + +Bases: mpf.core.mode_device.ModeDevice + +An achievement group in a pinball machine. It is tracked per player and can automatically restore state on the next ball. + +## Accessing achievement_groups in code + +The device collection which contains the achievement_groups in your machine is available via `self.machine.achievement_groups`. For example, to access one called “foo”, you would use `self.machine.achievement_groups.foo`. You can also access `achievement_groups` in dictionary form, e.g. `self.machine.achievement_groups['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Achievement_groups have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable achievement group. + +`enable()` + +Enable achievement group. + +`enabled` + +Return enabled state. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_rotate_left(**kwargs)` + +Event handler for rotate_left event. + +`event_rotate_right(reverse=False, **kwargs)` + +Event handler for rotate_right event. + +`event_select_random_achievement(**kwargs)` + +Event handler for select_random_achievement event. + +`event_start_selected(**kwargs)` + +Event handler for start_selected event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`member_state_changed(**kwargs)` + +Notify the group that one of its members has changed state. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`rotate_left()` + +Rotate to the left. + +`rotate_right(reverse=False)` + +Rotate to the right. + +`select_random_achievement()` + +Select a random achievement. + +`start_selected()` + +Start the currently selected achievement. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/achievements.md b/docs/code/api_reference/devices/achievements.md new file mode 100644 index 0000000000..95da4edc67 --- /dev/null +++ b/docs/code/api_reference/devices/achievements.md @@ -0,0 +1,109 @@ + +# self.machine.achievements.* + +`class mpf.devices.achievement.Achievement(*args, **kwargs)` + +Bases: mpf.core.mode_device.ModeDevice + +An achievement in a pinball machine. It is tracked per player and can automatically restore state on the next ball. + +## Accessing achievements in code + +The device collection which contains the achievements in your machine is available via `self.machine.achievements`. For example, to access one called “foo”, you would use `self.machine.achievements.foo`. You can also access achievements in dictionary form, e.g. `self.machine.achievements['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Achievements have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`can_be_selected_for_start` + +Return if this achievement can be selected and started. + +`complete()` + +Complete achievement. + +`disable()` + +Disable achievement. + +`enable()` + +Enable the achievement. It can only start if it was enabled before. + +`event_complete(**kwargs)` + +Event handler for complete event. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`event_select(**kwargs)` + +Event handler for select event. + +`event_start(**kwargs)` + +Event handler for start event. + +`event_stop(**kwargs)` + +Event handler for stop event. + +`event_unselect(**kwargs)` + +Event handler for unselect event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset the achievement to its initial state. + +`select()` + +Highlight (select) this achievement. + +`selected` + +Return current selection state. + +`start()` + +Start achievement. + +`state` + +Return current state. + +`stop()` + +Stop achievement. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`unselect()` + +Remove highlight (unselect) this achievement. + diff --git a/docs/code/api_reference/devices/autofires.md b/docs/code/api_reference/devices/autofires.md new file mode 100644 index 0000000000..f243fb414a --- /dev/null +++ b/docs/code/api_reference/devices/autofires.md @@ -0,0 +1,57 @@ + +# self.machine.autofires.* + +`class mpf.devices.autofire.AutofireCoil(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Autofire coils which fire based on switch hits with a hardware rule. Coils in the pinball machine which should fire automatically based on switch hits using defined hardware switch rules. Autofire coils work with rules written to the hardware pinball controller that allow them to respond “instantly” to switch hits versus waiting for the lag of USB and the host computer. Examples of Autofire Coils are pop bumpers, slingshots, and kicking targets. (Flippers use the same autofire rules under the hood, but flipper devices have their own device type in MPF. + +## Accessing autofires in code + +The device collection which contains the autofires in your machine is available via `self.machine.autofires`. For example, to access one called “foo”, you would use self.machine.autofires.foo. You can also access autofires in dictionary form, e.g. `self.machine.autofires['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Autofires have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable the autofire device. This is typically called at the end of a ball and when a tilt event happens. + +Parameters: + +* ****kwargs** – Not used, just included so this method can be used as an event callback. + +`enable()` + +Enable the autofire device. This causes the coil to respond to the switch hits. This is typically called when a ball starts to enable the slingshots, pops, etc. Note that there are several options for both the coil and the switch which can be incorporated into this rule, including recycle times, switch debounce, reversing the switch (fire the coil when the switch goes inactive), etc. These rules vary by hardware platform. See the user documentation for the hardware platform for details. + +Parameters: + +* ****kwargs** – Not used, just included so this method can be used as an event callback. + +`event_disable(**kwargs)` + +Handle disable control event. To prevent multiple rules at the same time we prioritize disable > enable. + +`event_enable(**kwargs)` + +Handle enable control event. To prevent multiple rules at the same time we prioritize disable > enable. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/ball_devices.md b/docs/code/api_reference/devices/ball_devices.md new file mode 100644 index 0000000000..2c38325764 --- /dev/null +++ b/docs/code/api_reference/devices/ball_devices.md @@ -0,0 +1,184 @@ + +self.machine.ball_devices.* + +`class mpf.devices.ball_device.ball_device.BallDevice(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Base class for a ‘Ball Device’ in a pinball machine. A ball device is anything that can hold one or more balls, such as a trough, an eject hole, a VUK, a catapult, etc. + +Args: Same as Device. + +## Accessing ball_devices in code + +The device collection which contains the ball_devices in your machine is available via self.machine.ball_devices. For example, to access one called “foo”, you would use `self.machine.ball_devices.foo`. You can also access `ball_devices` in dictionary form, e.g. `self.machine.ball_devices['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +`Ball_devices` have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_incoming_ball(incoming_ball: mpf.devices.ball_device.incoming_balls_handler.IncomingBall)` + +Notify this device that there is a ball heading its way. + +`available_balls` + +Number of balls that are available to be ejected. This differs from balls since it’s possible that this device could have balls that are being used for some other eject, and thus not available. + +`balls` + +Return the number of balls we expect in the near future. + +`cancel_path_if_target_is(start, target)` + +Check if the ball is going to a certain target and cancel the path in that case. + +`capacity` + +Return the ball capacity. + +`eject(balls=1, target=None) → int` + +Eject balls to target. Return the number of balls found for eject. The remaining balls are queued for eject when available. + +`eject_all(target=None) → bool` + +Eject all the balls from this device. + +Parameters: + +* **target** – The string or BallDevice target for this eject. Default of None means playfield. +* ****kwargs** – unused + +Returns True if there are balls to eject. False if this device is empty. + +`event_eject(balls=1, target=None, **kwargs)` + +Handle eject control event. + +`event_eject_all(target=None, **kwargs)` + +Handle eject_all control event. + +`event_entrance(**kwargs)` + +Event handler for entrance events. + +`event_request_ball(balls=1, **kwargs)` + +Handle request_ball control event. + +`expected_ball_received()` + + Handle an expected ball. + +`find_available_ball_in_path(start)` + +Try to remove available ball at the end of the path. + +`find_next_trough()` + +Find next trough after device. + +`find_one_available_ball(path=deque([]))` + +Find a path to a source device which has at least one available ball. + +`find_path_to_target(target)` + +Find a path to this target. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`handle_mechanial_eject_during_idle()` + +Handle mechanical eject. + +`classmethod is_playfield()` + +Return True if this ball device is a Playfield-type device, False if it’s a regular ball device. + +`lost_ejected_ball(target)` + +Handle an outgoing lost ball. + +`lost_idle_ball()` + +Lost an ball while the device was idle. + +`lost_incoming_ball(source)` + +Handle lost ball which was confirmed to have left source. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove_incoming_ball(incoming_ball: mpf.devices.ball_device.incoming_balls_handler.IncomingBall)` + +Remove a ball from the incoming balls queue. + +`request_ball(balls=1)` + +Request that one or more balls is added to this device. + +Parameters: + +* **balls** – Integer of the number of balls that should be added to this device. A value of -1 will cause this device to try to fill itself. +* ****kwargs** – unused + +`requested_balls` + +Return the number of requested balls. + +`result = None` + +`balldevice_(name)_ball_enter` A ball (or balls) have just entered the ball device called “name”. Note that this is a relay event based on the “unclaimed_balls” arg. Any unclaimed balls in the relay will be processed as new balls entering this device. Please be aware that we did not add those balls to balls or available_balls of the device during this event. + +args: + +* **unclaimed_balls**: The number of balls that have not yet been claimed. device: A reference to the ball device object that is posting this event. +* **Type**: event + +`set_eject_state(state)` + +Set the current device state. + +vsetup_eject_chain(path, player_controlled=False)` + +Set up an eject chain. + +`setup_eject_chain_next_hop(path, player_controlled)` + +Set up one hop of the eject chain. + +`setup_player_controlled_eject(target=None)` + +Set up a player controlled eject. + +`state` + +Return the device state. + +`stop_device()` + + Stop device. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`unexpected_ball_received()` + +Handle an unexpected ball. + +`wait_for_ready_to_receive(source)` + +Wait until this device is ready to receive a ball. + diff --git a/docs/code/api_reference/devices/ball_holds.md b/docs/code/api_reference/devices/ball_holds.md new file mode 100644 index 0000000000..933aaef046 --- /dev/null +++ b/docs/code/api_reference/devices/ball_holds.md @@ -0,0 +1,105 @@ + +# self.machine.ball_holds.* + +`class mpf.devices.ball_hold.BallHold(*args, **kwargs)` + +Bases: mpf.core.enable_disable_mixin.EnableDisableMixin, mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +Ball hold device which can be used to keep balls in ball devices and control their eject later on. + +## Accessing ball_holds in code + +The device collection which contains the ball_holds in your machine is available via `self.machine.ball_holds`. For example, to access one called “foo”, you would use `self.machine.ball_holds.foo`. You can also access ball_holds in dictionary form, e.g. `self.machine.ball_holds['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Ball_holds have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable device. + +`enable() → None` + +Enable device. + +`enabled` + +Return true if enabled. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_release_all(**kwargs)` + +Event handler for release_all event. + +`event_release_one(**kwargs)` + +Event handler for release_one event. + +`event_release_one_if_full(**kwargs)` + +Event handler for release_one_if_full event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`is_full()` + +Return true if hold is full. + +`persist_enabled` + +Return if enabled is persisted. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`release_all()` + +Release all balls in hold. + +`release_balls(balls_to_release)` + +Release all balls and return the actual amount of balls released. + +Parameters: + +* **balls_to_release** – number of ball to release from hold + +`release_one()` + +Release one ball. + +`release_one_if_full()` + +Release one ball if hold is full. + +`remaining_space_in_hold()` + +Return the remaining capacity of the hold. + +`reset()` + +Reset the hold. Will release held balls. Device status will stay the same (enabled/disabled). It will wait for those balls to drain and block ball_ending until they do. Those balls are not included in ball_in_play. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/ball_routings.md b/docs/code/api_reference/devices/ball_routings.md new file mode 100644 index 0000000000..be198eba4c --- /dev/null +++ b/docs/code/api_reference/devices/ball_routings.md @@ -0,0 +1,57 @@ + +# self.machine.ball_routings.* + +`class mpf.devices.ball_routing.BallRouting(*args, **kwargs)` + +Bases: mpf.core.enable_disable_mixin.EnableDisableMixin, mpf.core.mode_device.ModeDevice + +Route balls from one device to another when captured. + +## Accessing ball_routings in code + +The device collection which contains the `ball_routings` in your machine is available via `self.machine.ball_routings`. For example, to access one called “foo”, you would use `self.machine.ball_routings.foo`. You can also access ball_routings in dictionary form, e.g. `self.machine.ball_routings['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Ball_routings have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable device. + +`enable() → None` + +Enable device. + +`enabled` + +Return true if enabled. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`persist_enabled` + +Return if enabled is persisted. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/ball_saves.md b/docs/code/api_reference/devices/ball_saves.md new file mode 100644 index 0000000000..c9b26d06c0 --- /dev/null +++ b/docs/code/api_reference/devices/ball_saves.md @@ -0,0 +1,73 @@ + +# self.machine.ball_saves.* + +`class mpf.devices.ball_save.BallSave(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +Ball save device which will give back the ball within a certain time. + +## Accessing ball_saves in code + +The device collection which contains the `ball_saves` in your machine is available via `self.machine.ball_saves`. For example, to access one called “foo”, you would use `self.machine.ball_saves.foo`. You can also access ball_saves in dictionary form, e.g. `self.machine.ball_saves['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Ball_saves have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`delayed_eject()` + +Trigger eject of all scheduled balls. + +`disable() → None` + +Disable ball save. + +`early_ball_save() → None` + +Perform early ball save if enabled. + +`enable() → None` + +Enable ball save. + +`event_delayed_eject(**kwargs)` + +Event handler for delayed_eject event. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_early_ball_save(**kwargs)` + +Event handler for early_ball_save event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_timer_start(**kwargs)` + +Event handler for timer start event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`timer_start() → None` + +Start the timer. This is usually called after the ball was ejected while the ball save may have been enabled earlier. + diff --git a/docs/code/api_reference/devices/coils.md b/docs/code/api_reference/devices/coils.md new file mode 100644 index 0000000000..e819630b31 --- /dev/null +++ b/docs/code/api_reference/devices/coils.md @@ -0,0 +1,78 @@ + +self.machine.coils.* + + +`class mpf.devices.driver.Driver(machine: mpf.core.machine.MachineController, name: str)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Generic class that holds driver objects. A ‘driver’ is any device controlled from a driver board which is typically the high-voltage stuff like coils and flashers. This class exposes the methods you should use on these driver types of devices. Each platform module (i.e. P-ROC, FAST, etc.) subclasses this class to actually communicate with the physical hardware and perform the actions. + +Args: Same as the Device parent class + +## Accessing coils in code + +The device collection which contains the coils in your machine is available via `self.machine.coils`. For example, to access one called “foo”, you would use `self.machine.coils.foo`. You can also access coils in dictionary form, e.g. `self.machine.coils['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Coils have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable this driver. + +`enable(pulse_ms: int = None, pulse_power: float = None, hold_power: float = None)` + +Enable a driver by holding it ‘on’. + +Parameters: + +* **pulse_ms** – The number of milliseconds the driver should be enabled for. If no value is provided, the driver will be enabled for the value specified in the config dictionary. +* **pulse_power** – The pulse power. A float between 0.0 and 1.0. +* **hold_power** – The pulse power. A float between 0.0 and 1.0. + +If this driver is configured with a holdpatter, then this method will use that holdpatter to pwm pulse the driver. If not, then this method will just enable the driver. As a safety precaution, if you want to enable() this driver without pwm, then you have to add the following option to this driver in your machine configuration files: `allow_enable: True` + +`event_disable(**kwargs)` + +Event handler for disable control event. + +`event_enable(pulse_ms: int = None, pulse_power: float = None, hold_power: float = None, **kwargs)` + +Event handler for control enable. + +`event_pulse(pulse_ms: int = None, pulse_power: float = None, max_wait_ms: int = None, **kwargs) → None` + +Event handler for pulse control events. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_and_verify_hold_power(hold_power: Optional[float]) → float` + +Return the hold power to use. If hold_power is None it will use the default_hold_power. Additionally it will verify the limits. + +`get_and_verify_pulse_ms(pulse_ms: Optional[int]) → int` + +Return and verify pulse_ms to use. If pulse_ms is None return the default. + +`get_and_verify_pulse_power(pulse_power: Optional[float]) → float` + +Return the pulse power to use. If pulse_power is None it will use the default_pulse_power. Additionally it will verify the limits. + +`pulse(pulse_ms: int = None, pulse_power: float = None, max_wait_ms: int = None) → int` + +Pulse this driver. + +Parameters: + +* **pulse_ms** – The number of milliseconds the driver should be enabled for. If no value is provided, the driver will be enabled for the value specified in the config dictionary. +* **pulse_power** – The pulse power. A float between 0.0 and 1.0. +* **max_wait_ms** – Maximum time this pulse may be delayed for PSU optimization. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/combo_switches.md b/docs/code/api_reference/devices/combo_switches.md new file mode 100644 index 0000000000..5955f058a7 --- /dev/null +++ b/docs/code/api_reference/devices/combo_switches.md @@ -0,0 +1,45 @@ + +# self.machine.combo_switches.* + +`class mpf.devices.combo_switch.ComboSwitch(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +Combo Switch device. + +## Accessing combo_switches in code + +The device collection which contains the `combo_switches` in your machine is available via `self.machine.combo_switches`. For example, to access one called “foo”, you would use `self.machine.combo_switches.foo`. You can also access combo_switches in dictionary form, e.g. `self.machine.combo_switches['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Combo_switches have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enable() → None` + +Enable handler. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`state` + +Return current state. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/counters.md b/docs/code/api_reference/devices/counters.md new file mode 100644 index 0000000000..23226e4925 --- /dev/null +++ b/docs/code/api_reference/devices/counters.md @@ -0,0 +1,128 @@ + +# self.machine.counters.* + +`class mpf.devices.logic_blocks.Counter(machine: mpf.core.machine.MachineController, name: str)` + +Bases: mpf.devices.logic_blocks.LogicBlock + +A type of LogicBlock that tracks multiple hits of a single event. This counter can be configured to track hits towards a specific end-goal (like number of tilt hits to tilt), or it can be an open-ended count (like total number of ramp shots). It can also be configured to count up or to count down, and can have a configurable counting interval. + +## Accessing counters in code + +The device collection which contains the counters in your machine is available via `self.machine.counters`. For example, to access one called “foo”, you would use `self.machine.counters.foo`. You can also access counters in dictionary form, e.g. `self.machine.counters['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Counters have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`check_complete(count_complete_value=None)` + +Check if counter is completed. Return true if the counter has reached or surpassed its specified completion value, return False if no completion criteria or is not complete. + +`complete()` + +Mark this logic block as complete. Posts the`events_when_complete` events and optionally restarts this logic block or disables it, depending on this block’s configuration settings. + +`completed` + +Return if completed. + +`count()` + +Increase the hit progress towards completion. This method is also automatically called when one of the count_events is posted. + +`disable()` + +Disable this logic block. Automatically called when one of the disable_event events is posted. Can also manually be called. + +`enable()` + +Enable this logic block. Automatically called when one of the enable_event events is posted. Can also manually be called. + +`enabled` + +Return if enabled. + +`event_add(value, **kwargs)` + +Add to the value of this counter. + +Parameters: + +* **value** – Value to add to the counter. +* **kwargs** – Additional arguments. + +`event_count(**kwargs)` + +Event handler for count events. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_jump(value, **kwargs)` + +Set the internal value of the counter. + +Parameters: + +* **value** – Value to add to jump to. +* **kwargs** – Additional arguments. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`event_restart(**kwargs)` + +Event handler for restart event. + +`event_subtract(value, **kwargs)` + +Subtract from the value of this counter. + +Parameters: + +* **value** – Value to subtract from the counter. +* **kwargs** – Additional arguments. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`get_start_value() → int` + +Return start count. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset the progress towards completion of this logic block. Automatically called when one of the reset_event events is called. Can also be manually called. + +`restart()` + +Restart this logic block by calling reset() and enable(). Automatically called when one of the restart_event events is called. Can also be manually called. + +`stop_ignoring_hits(**kwargs)` + +Cause the Counter to stop ignoring subsequent hits that occur within the ‘multiple_hit_window’. Automatically called when the window time expires. Can safely be manually called. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`value` + +Return value or None if that is currently not possible. + diff --git a/docs/code/api_reference/devices/digital_outputs.md b/docs/code/api_reference/devices/digital_outputs.md new file mode 100644 index 0000000000..9fc68ceee3 --- /dev/null +++ b/docs/code/api_reference/devices/digital_outputs.md @@ -0,0 +1,49 @@ + +# self.machine.digital_outputs.* + +`class mpf.devices.digital_output.DigitalOutput(machine: mpf.core.machine.MachineController, name: str)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +A digital output on either a light or driver platform. + +## Accessing digital_outputs in code + +The device collection which contains the `digital_outputs` in your machine is available via `self.machine.digital_outputs`. For example, to access one called “foo”, you would use `self.machine.digital_outputs.foo`. You can also access digital_outputs in dictionary form, e.g. `self.machine.digital_outputs['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Digital_outputs have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable digital output. + +`enable()` + +Enable digital output. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_pulse(pulse_ms, **kwargs)` + +Handle pulse control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`pulse(pulse_ms)` + +Pulse digital output. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/diverters.md b/docs/code/api_reference/devices/diverters.md new file mode 100644 index 0000000000..663fec89ff --- /dev/null +++ b/docs/code/api_reference/devices/diverters.md @@ -0,0 +1,90 @@ + +# self.machine.diverters.* + +`class mpf.devices.diverter.Diverter(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a diverter in a pinball machine. + +Args: Same as the Device parent class. + +## Accessing diverters in code + +The device collection which contains the `diverters` in your machine is available via `self.machine.diverters`. For example, to access one called “foo”, you would use `self.machine.diverters.foo`. You can also access diverters in dictionary form, e.g. `self.machine.diverters['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Diverters have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`activate()` + +Physically activate this diverter’s coil. + +`deactivate()` + +Deactivate this diverter. This method will disable the activation_coil, and (optionally) if it’s configured with a deactivation coil, it will pulse it. + +`disable(auto=False)` + +Disable this diverter. This method will remove the hardware rule if this diverter is activated via a hardware switch. + +Parameters: + +* **auto** – Boolean value which is used to indicate whether this diverter disabled itself automatically. This is passed to the event which is posted. +* ****kwargs** – This is here because this disable method is called by whatever event the game programmer specifies in their machine configuration file, so we don’t know what event that might be or whether it has random kwargs attached to it. + +`enable(auto=False)` + +Enable this diverter. + +Parameters: + +* **auto** – Boolean value which is used to indicate whether this diverter enabled itself automatically. This is passed to the event which is posted. + +If an `activation_switches` is configured, then this method writes a hardware autofire rule to the pinball controller which fires the diverter coil when the switch is activated. If no activation_switches is specified, then the diverter is activated immediately. + +`event_activate(**kwargs)` + +Handle activate control event. + +`event_deactivate(**kwargs)` + +Handle deactivate control event. + +`event_disable(auto=False, **kwargs)` + +Handle disable control event. + +`event_enable(auto=False, **kwargs)` + +Handle enable control event. + +`event_reset(**kwargs)` + +Handle reset control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset and deactivate the diverter. + +`schedule_deactivation()` + +Schedule a delay to deactivate this diverter. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/dmds.md b/docs/code/api_reference/devices/dmds.md new file mode 100644 index 0000000000..776a2c89be --- /dev/null +++ b/docs/code/api_reference/devices/dmds.md @@ -0,0 +1,31 @@ +# self.machine.dmds.* + +`class mpf.devices.dmd.Dmd(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +A physical DMD. + +## Accessing dmds in code + +The device collection which contains the dmds in your machine is available via `self.machine.dmds`. For example, to access one called “foo”, you would use `self.machine.dmds.foo`. You can also access dmds in dictionary form, e.g. `self.machine.dmds['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Dmds have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`update(data: bytes)` + +Update data on the dmd. + +Parameters: + +* **data** – bytes to send diff --git a/docs/code/api_reference/devices/drop_target_banks.md b/docs/code/api_reference/devices/drop_target_banks.md new file mode 100644 index 0000000000..1f08bad91e --- /dev/null +++ b/docs/code/api_reference/devices/drop_target_banks.md @@ -0,0 +1,53 @@ + +# self.machine.drop_target_banks.* + +`class mpf.devices.drop_target.DropTargetBank(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +A bank of drop targets in a pinball machine by grouping together multiple DropTarget class devices. + +## Accessing drop_target_banks in code + +The device collection which contains the `drop_target_banks` in your machine is available via `self.machine.drop_target_banks`. For example, to access one called “foo”, you would use `self.machine.drop_target_banks.foo`. You can also access drop_target_banks in dictionary form, e.g. `self.machine.drop_target_banks['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Drop_target_banks have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enable() → None` + +Enable handler. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_reset(**kwargs)` + +Handle reset control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`member_target_change()` + +Handle that a member drop target has changed state. This method causes this group to update its down and up counts and complete status. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset this bank of drop targets. This method has some intelligence to figure out what coil(s) it should fire. It builds up a set by looking at its own reset_coil and reset_coils settings, and also scanning through all the member drop targets and collecting their coils. Then it pulses each of them. (This coil list is a “set” which means it only sends a single pulse to each coil, even if each drop target is configured with its own coil.) + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/drop_targets.md b/docs/code/api_reference/devices/drop_targets.md new file mode 100644 index 0000000000..0e1d08496d --- /dev/null +++ b/docs/code/api_reference/devices/drop_targets.md @@ -0,0 +1,86 @@ + +# self.machine.drop_targets.* + +`class mpf.devices.drop_target.DropTarget(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a single drop target in a pinball machine. + +Args: Same as the Target parent class + +## Accessing drop_targets in code + +The device collection which contains the `drop_targets` in your machine is available via `self.machine.drop_targets`. For example, to access one called “foo”, you would use `self.machine.drop_targets.foo`. You can also access drop_targets in dictionary form, e.g. `self.machine.drop_targets['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Drop_targets have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_to_bank(bank)` + +Add this drop target to a drop target bank. This allows the bank to update its status based on state changes to this drop target. + +Parameters: +* **bank** – DropTargetBank object to add this drop target to. + +`disable_keep_up()` + +No longer keep up the target up. + +`enable_keep_up()` + +Keep the target up by enabling the coil. + +`event_disable_keep_up(**kwargs)` + +Handle disable_keep_up control event. + +`event_enable_keep_up(**kwargs)` + +Handle enable_keep_up control event. + +`event_knockdown(**kwargs)` + +Handle knockdown control event. + +`event_reset(**kwargs)` + +Handle reset control event. + +`external_reset_from_bank()` + +Handle the reset from our bank. The bank might pulse the coil from this device or it might have a separate reset coil which will trigger a reset on switch of this device. Make sure we do not mark the playfield as active. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`knockdown()` + +Pulse the knockdown coil to knock down this drop target. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove_from_bank(bank)` + +Remove the DropTarget from a bank. + +Parameters: + +* **bank** – DropTargetBank object to remove + +`reset()` + +Reset this drop target. If this drop target is configured with a reset coil, then this method will pulse that coil. If not, then it checks to see if this drop target is part of a drop target bank, and if so, it calls the reset() method of the drop target bank. This method does not reset the target profile, however, the switch event handler should reset the target profile on its own when the drop target physically moves back to the up position. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/dual_wound_coils.md b/docs/code/api_reference/devices/dual_wound_coils.md new file mode 100644 index 0000000000..754d4124a9 --- /dev/null +++ b/docs/code/api_reference/devices/dual_wound_coils.md @@ -0,0 +1,54 @@ + +# self.machine.dual_wound_coils.* + +`class mpf.devices.dual_wound_coil.DualWoundCoil(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +An instance of a dual wound coil which consists of two coils. + +## Accessing dual_wound_coils in code + +The device collection which contains the `dual_wound_coils` in your machine is available via `self.machine.dual_wound_coils`. For example, to access one called “foo”, you would use `self.machine.dual_wound_coils.foo`. You can also access dual_wound_coils in dictionary form, e.g. `self.machine.dual_wound_coils['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Dual_wound_coils have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable a driver. + +`enable()` + +Enable a dual wound coil. Pulse main coil and enable hold coil. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_pulse(milliseconds: int = None, power: float = None, **kwargs)` + +Event handler for pulse event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + + `pulse(milliseconds: int = None, power: float = None)` + +Pulse this driver. + +Parameters: + +* **milliseconds** – The number of milliseconds the driver should be enabled for. If no value is provided, the driver will be enabled for the value specified in the config dictionary. +* **power** – A multiplier that will be applied to the default pulse time, typically a float between 0.0 and 1.0. (Note this is can only be used if milliseconds is also specified.) + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/extra_ball_groups.md b/docs/code/api_reference/devices/extra_ball_groups.md new file mode 100644 index 0000000000..3e29f3fc79 --- /dev/null +++ b/docs/code/api_reference/devices/extra_ball_groups.md @@ -0,0 +1,69 @@ + +# self.machine.extra_ball_groups.* + +class mpf.devices.extra_ball_group.ExtraBallGroup(*args, **kwargs) + + Bases: mpf.core.system_wide_device.SystemWideDevice + + Tracks and manages groups of extra balls devices. + +## Accessing extra_ball_groups in code + +The device collection which contains the `extra_ball_groups` in your machine is available via `self.machine.extra_ball_groups`. For example, to access one called “foo”, you would use `self.machine.extra_ball_groups.foo`. You can also access extra_ball_groups in dictionary form, e.g. `self.machine.extra_ball_groups['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Extra_ball_groups have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`award(posted_unlit_events=False)` + +Immediately awards an extra ball. This event first checks to make sure the limits of the max extra balls have not been exceeded and that this group is enabled. Note that this method will work even if this group does not have any extra balls or extra balls lit. You can use this to directly award an extra ball. + +`award_disabled()` + +Post the events when an extra ball connect be awarded. + +`award_lit()` + +Award a lit extra ball. If the player does not have any lit extra balls, this method does nothing. + +`enabled` + +Return whether this extra ball group is enabled. This attribute considers the enabled setting plus the max balls per game and ball settings. + +`event_award(posted_unlit_events=False, **kwargs)` + +Handle award control event. + +`event_award_lit(**kwargs)` + +Handle award_lit control event. + +`event_light(**kwargs)` + +Handle light control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`is_ok_to_light() → bool` + +Check if it’s possible to light an extra ball. Returns True or False. This method checks to see if the group is enabled and whether the max_lit setting has been exceeded. + +`light()` + +Light the extra ball for possible collection by the player. This method checks that the group is enabled and that the max lit value has not been exceeded. If so, this method will post the extra ball disabled events. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/extra_balls.md b/docs/code/api_reference/devices/extra_balls.md new file mode 100644 index 0000000000..ab5534b67b --- /dev/null +++ b/docs/code/api_reference/devices/extra_balls.md @@ -0,0 +1,77 @@ + +# self.machine.extra_balls.* + +`class mpf.devices.extra_ball.ExtraBall(*args, **kwargs)` + +Bases: mpf.core.mode_device.ModeDevice + +An extra ball which can be awarded once per player. + +## Accessing extra_balls in code + +The device collection which contains the `extra_balls` in your machine is available via `self.machine.extra_balls`. For example, to access one called “foo”, you would use `self.machine.extra_balls.foo`. You can also access extra_balls in dictionary form, e.g. `self.machine.extra_balls['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Extra_balls have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`award()` + +Award extra ball to player (if enabled). + +`enable() → None` + +Enable handler. + +`enabled` + +Return whether this extra ball group is enabled. This takes into consideration the enabled setting plus the max balls per game setting. + +`event_award(**kwargs)` + +Handle award control event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_light(**kwargs)` + +Handle light control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`group` + +The ExtraBallGroup this ExtraBall belongs to, or None. + +`is_ok_to_award() → bool` + +Check whether this extra ball can be awarded. This method takes into consideration whether this extra ball is enabled, whether the max_per_game has been exceeded, and, if this extra ball is a member of a group, whether the group is enabled and will allow an additional extra ball to be awarded. Returns True or False. + +`is_ok_to_light() → bool` + +Check whether this extra ball can be lit. This method takes into consideration whether this extra ball is enabled, and, if this extra ball is a member of a group, whether the group is enabled and will allow an additional extra ball to lit. Returns True or False. + +`light()` + +Light an extra ball for potential collection by the player. Lighting an extra ball will immediately increase count against the max_per_game setting, even if the extra ball is a member of a group that’s disabled or if the player never actually collects the extra ball. Note that this only really does anything if this extra ball is a member of a group. + +`player` + +The current player + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/flippers.md b/docs/code/api_reference/devices/flippers.md new file mode 100644 index 0000000000..daa2897108 --- /dev/null +++ b/docs/code/api_reference/devices/flippers.md @@ -0,0 +1,80 @@ + +# self.machine.flippers.* + +`class mpf.devices.flipper.Flipper(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a flipper in a pinball machine. Subclass of Device. Contains several methods for actions that can be performed on this flipper, like enable(), disable(), etc. Flippers have several options, including player buttons, EOS swtiches, multiple coil options (pulsing, hold coils, etc.) + +Parameters: + +* **machine** – A reference to the machine controller instance. +* **name** – A string of the name you’ll refer to this flipper object as. + +## Accessing flippers in code + +The device collection which contains the `flippers` in your machine is available via `self.machine.flippers`. For example, to access one called “foo”, you would use `self.machine.flippers.foo`. You can also access flippers in dictionary form, e.g. `self.machine.flippers['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Flippers have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable the flipper. This method makes it so the cabinet flipper buttons no longer control the flippers. Used when no game is active and when the player has tilted. + +`enable()` + +Enable the flipper by writing the necessary hardware rules to the hardware controller. The hardware rules for coils can be kind of complex given all the options, so we’ve mapped all the options out here. We literally have methods to enable the various rules based on the rule letters here, which we’ve implemented below. Keeps it easy to understand. Note there’s a platform feature saved at: `self.machine.config['platform']['hw_enable_auto_disable']`. If True, it means that the platform hardware rules will automatically disable a coil that has been enabled when the trigger switch is disabled. If False, it means the hardware platform needs its own rule to disable the coil when the switch is disabled. Methods F and G below check for that feature setting and will not be applied to the hardware if it’s True. + +Two coils, using EOS switch to indicate the end of the power stroke: Rule Type Coil Switch Action A. Enable Main Button active D. Enable Hold Button active E. Disable Main EOS active + +One coil, using EOS switch: Rule Type Coil Switch Action A. Enable Main Button active H. PWM Main EOS active + +Two coils, not using EOS switch: Rule Type Coil Switch Action B. Pulse Main Button active D. Enable Hold Button active + +One coil, not using EOS switch: Rule Type Coil Switch Action C. Pulse/PWM Main button active + +Use EOS switch for safety (for platforms that support multiple switch rules). Note that this rule is the letter “i”, not a numeral 1. I. Enable power if button is active and EOS is not active + +`event_disable(**kwargs)` + +Handle disable control event. To prevent multiple rules at the same time we prioritize disable > enable. + +`event_enable(**kwargs)` + +Handle enable control event. To prevent multiple rules at the same time we prioritize disable > enable. + +`event_sw_flip(**kwargs)` + +Handle sw_flip control event. + +`event_sw_release(**kwargs)` + +Handle sw_release control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`sw_flip()` + +Activate the flipper via software as if the flipper button was pushed. This is needed because the real flipper activations are handled in hardware, so if you want to flip the flippers with the keyboard or OSC interfaces, you have to call this method. Note this method will keep this flipper enabled until you call sw_release(). + +`sw_release()` + +Deactivate the flipper via software as if the flipper button was released. See the documentation for sw_flip() for details. + diff --git a/docs/code/api_reference/devices/hardware_sound_systems.md b/docs/code/api_reference/devices/hardware_sound_systems.md new file mode 100644 index 0000000000..1531c69645 --- /dev/null +++ b/docs/code/api_reference/devices/hardware_sound_systems.md @@ -0,0 +1,53 @@ + +# self.machine.hardware_sound_systems.* + +`class mpf.devices.hardware_sound_system.HardwareSoundSystem(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Hardware sound system using in EM and SS machines. + +## Accessing hardware_sound_systems in code + +The device collection which contains the `hardware_sound_systems` in your machine is available via `self.machine.hardware_sound_systems`. For example, to access one called “foo”, you would use `self.machine.hardware_sound_systems.foo`. You can also access hardware_sound_systems in dictionary form, e.g. `self.machine.hardware_sound_systems['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Hardware_sound_systems have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`decrease_volume(volume: float, track: int = 1)` + +Increase volume. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`increase_volume(volume: float, track: int = 1)` + +Increase volume. + +`play(sound_number: int, track: int = 1)` + +Play a sound. + +`play_file(file: str, platform_options, track: int = 1)` + +Play a sound file. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`set_volume(volume: float, track: int = 1)` + +Set volume. + +`stop_all_sounds(track: int = 1)` + +Stop all sounds on track. + +`text_to_speech(text: str, platform_options, track: int = 1)` + +Text to speech output. + diff --git a/docs/code/api_reference/devices/kickbacks.md b/docs/code/api_reference/devices/kickbacks.md new file mode 100644 index 0000000000..31e27370c2 --- /dev/null +++ b/docs/code/api_reference/devices/kickbacks.md @@ -0,0 +1,67 @@ + +# self.machine.kickbacks.* + +`class mpf.devices.kickback.Kickback(*args, **kwargs)` + +Bases: mpf.devices.autofire.AutofireCoil + +A kickback device which will fire a ball back into the playfield. + +## Accessing kickbacks in code + +The device collection which contains the kickbacks in your machine is available via `self.machine.kickbacks`. For example, to access one called “foo”, you would use `self.machine.kickbacks.foo`. You can also access kickbacks in dictionary form, e.g. `self.machine.kickbacks['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Kickbacks have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable the autofire device. + +This is typically called at the end of a ball and when a tilt event happens. + +Parameters: + +* ****kwargs** – Not used, just included so this method can be used as an event callback. + +`enable()` + +Enable the autofire device. + +This causes the coil to respond to the switch hits. This is typically called when a ball starts to enable the slingshots, pops, etc. + +Note that there are several options for both the coil and the switch which can be incorporated into this rule, including recycle times, switch debounce, reversing the switch (fire the coil when the switch goes inactive), etc. These rules vary by hardware platform. See the user documentation for the hardware platform for details. + +Parameters: + +* ****kwargs** – Not used, just included so this method can be used as an event callback. + +`event_disable(**kwargs)` + +Handle disable control event. + +To prevent multiple rules at the same time we prioritize disable > enable. + +`event_enable(**kwargs)` + +Handle enable control event. + +To prevent multiple rules at the same time we prioritize disable > enable. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/light_rings.md b/docs/code/api_reference/devices/light_rings.md new file mode 100644 index 0000000000..5d325410d6 --- /dev/null +++ b/docs/code/api_reference/devices/light_rings.md @@ -0,0 +1,33 @@ + +# self.machine.light_rings.* + +`class mpf.devices.light_group.LightRing(machine: mpf.core.machine.MachineController, name)` + +Bases: mpf.devices.light_group.LightGroup + +A light ring. + +## Accessing light_rings in code + +The device collection which contains the `light_rings` in your machine is available via `self.machine.light_rings`. For example, to access one called “foo”, you would use `self.machine.light_rings.foo`. You can also access `light_rings` in dictionary form, e.g. `self.machine.light_rings['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Light_rings have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`color(color, fade_ms=None, priority=0, key=None)` + +Call color on all lights in this group. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_token()` + +Return all lights in group as token. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/light_stripes.md b/docs/code/api_reference/devices/light_stripes.md new file mode 100644 index 0000000000..133b72eeed --- /dev/null +++ b/docs/code/api_reference/devices/light_stripes.md @@ -0,0 +1,34 @@ + +self.machine.light_stripes.* + +`class mpf.devices.light_group.LightStrip(machine: mpf.core.machine.MachineController, name)` + +Bases: mpf.devices.light_group.LightGroup + +A light strip. + +## Accessing light_stripes in code + +The device collection which contains the `light_stripes` in your machine is available via `self.machine.light_stripes`. For example, to access one called “foo”, you would use `self.machine.light_stripes.foo`. You can also access `light_stripes` in dictionary form, e.g. `self.machine.light_stripes['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Light_stripes have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + + +`color(color, fade_ms=None, priority=0, key=None)` + +Call color on all lights in this group. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_token()` + +Return all lights in group as token. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/lights.md b/docs/code/api_reference/devices/lights.md new file mode 100644 index 0000000000..ddd1a66175 --- /dev/null +++ b/docs/code/api_reference/devices/lights.md @@ -0,0 +1,171 @@ + +# self.machine.lights.* + +`class mpf.devices.light.Light(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.devices.device_mixins.DevicePositionMixin + +A light in a pinball machine. + +## Accessing lights in code + +The device collection which contains the lights in your machine is available via `self.machine.lights`. For example, to access one called “foo”, you would use `self.machine.lights.foo`. You can also access lights in dictionary form, e.g. `self.machine.lights['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Lights have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_stack()` + +Remove all entries from the stack and resets this light to ‘off’. + +`color(color, fade_ms=None, priority=0, key=None, start_time=None)` + +Add or update a color entry in this light’s stack. + +Calling this methods is how you tell this light what color you want it to be. + +Parameters: + +* **color** – RGBColor() instance, or a string color name, hex value, or 3-integer list/tuple of colors. +* **fade_ms** – Int of the number of ms you want this light to fade to the color in. A value of 0 means it’s instant. A value of None (the default) means that it will use this light’s and/or the machine’s default fade_ms setting. +* **priority** – Int value of the priority of these incoming settings. If this light has current settings in the stack at a higher priority, the settings you’re adding here won’t take effect. However they’re still added to the stack, so if the higher priority settings are removed, then the next-highest apply. +* **key** – An arbitrary identifier (can be any immutable object) that’s used to identify these settings for later removal. If any settings in the stack already have this key, those settings will be replaced with these new settings. +* **start_time** – Time this occured to synchronize lights. + +`color_correct(color)` + +Apply the current color correction profile to the color passed. + +Parameters: + +* **color** – The RGBColor() instance you want to get color corrected. + +Returns an updated RGBColor() instance with the current color correction profile applied. + +Note that if there is no current color correction profile applied, the returned color will be the same as the color that was passed. + +`fade_in_progress` + +Return true if a fade is in progress. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`gamma_correct(color)` + +Apply max brightness correction to color. +Parameters: + +* **color** – The RGBColor() instance you want to have gamma applied. + +Returns an updated RGBColor() instance with gamma corrected. + +`get_color()` + +Return an RGBColor() instance of the ‘color’ setting of the highest color setting in the stack. + +This is usually the same color as the physical light, but not always (since physical lights are updated once per frame, this value could vary. + +Also note the color returned is the “raw” color that does has not had the color correction profile applied. + +`get_color_below(priority, key)` + +Return an RGBColor() instance of the ‘color’ setting of the highest color below a certain key. + +Similar to get_color. + +`get_hw_numbers()` + +Return a list of all hardware driver numbers. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`get_successor_number()` + +Get the number of the next light channel. + +We first have to find the last channel and then get the next number based on that. + +`off(fade_ms=None, priority=0, key=None, **kwargs)` + +Turn light off. + +Parameters: + +* **key** – key for removal later on +* **priority** – priority on stack +* **fade_ms** – duration of fade + +`on(brightness=None, fade_ms=None, priority=0, key=None, **kwargs)` + +Turn light on. + +Parameters: + +* **brightness** – Brightness factor for “on”. +* **key** – key for removal later on +* **priority** – priority on stack +* **fade_ms** – duration of fade + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove_from_stack_by_key(key, fade_ms=None)` + +Remove a group of color settings from the stack. + +Parameters: + +* **key** – The key of the settings to remove (based on the ‘key’ parameter that was originally passed to the color() method.) +* **fade_ms** – Time to fade out the light. + +This method triggers a light update, so if the highest priority settings were removed, the light will be updated with whatever’s below it. If no settings remain after these are removed, the light will turn off. + +`stack` + +A list of dicts which represents different commands that have come in to set this light to a certain color (and/or fade). Each entry in the list contains the following key/value pairs: + + `priority`: + The relative priority of this color command. Higher numbers take precedent, and the highest priority entry will be the command that’s currently active. In the event of a tie, whichever entry was added last wins (based on ‘start_time’ below). + `start_time`: + The clock time when this command was added. Primarily used to calculate fades, but also used as a tie-breaker for multiple entries with the same priority. + `start_color`: + RGBColor() of the color of this light when this command came in. + `dest_time`: + Clock time that represents when a fade (from start_color to dest_color) will be done. If this is 0, that means there is no fade. When a fade is complete, this value is reset to 0. + `dest_color`: + RGBColor() of the destination this light is fading to. If a command comes in with no fade, then this will be the same as the ‘color’ below. + `key`: + An arbitrary unique identifier to keep multiple entries in the stack separate. If a new color command comes in with a key that already exists for an entry in the stack, that entry will be replaced by the new entry. The key is also used to remove entries from the stack (e.g. when shows or modes end and they want to remove their commands from the light). + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`wait_for_loaded()` + +Return future. + +`x` + +Get the X value from the config. + +Returns the devices x position from config + +`y` + +Get the Y value from the config. + +Returns the devices y position from config + +`z` + +Get the Z value from the config. + +Returns the devices z position from config + diff --git a/docs/code/api_reference/devices/magnets.md b/docs/code/api_reference/devices/magnets.md new file mode 100644 index 0000000000..6589765586 --- /dev/null +++ b/docs/code/api_reference/devices/magnets.md @@ -0,0 +1,81 @@ + +# self.machine.magnets.* + +`class mpf.devices.magnet.Magnet(*args, **kwargs)` + +Bases: mpf.core.enable_disable_mixin.EnableDisableMixinSystemWideDevice, mpf.core.system_wide_device.SystemWideDevice + +Controls a playfield magnet in a pinball machine. + +## Accessing magnets in code + +The device collection which contains the magnets in your machine is available via `self.machine.magnets`. For example, to access one called “foo”, you would use `self.machine.magnets.foo`. You can also access magnets in dictionary form, e.g. `self.machine.magnets['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Magnets have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable device. + +`enable() → None` + +Enable device. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_fling_ball(**kwargs)` + +Event handler for fling_ball event. + +`event_grab_ball(**kwargs)` + +Event handler for grab_ball event. + +`event_release_ball(**kwargs)` + +Event handler for release_ball event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`fling_ball()` + +Fling the grabbed ball. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`grab_ball()` + +Grab a ball. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`release_ball()` + +Release the grabbed ball. + +`reset()` + +Release ball and disable magnet. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/motors.md b/docs/code/api_reference/devices/motors.md new file mode 100644 index 0000000000..eb5e36fee3 --- /dev/null +++ b/docs/code/api_reference/devices/motors.md @@ -0,0 +1,49 @@ + +# self.machine.motors.* + +`class mpf.devices.motor.Motor(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +A motor which can be controlled using drivers. + +## Accessing motors in code + +The device collection which contains the motors in your machine is available via `self.machine.motors`. For example, to access one called “foo”, you would use `self.machine.motors.foo`. You can also access motors in dictionary form, e.g. `self.machine.motors['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Motors have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`event_go_to_position(position=None, **kwargs)` + +Event handler for go_to_position event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`go_to_position(position)` + +Move motor to a specific position. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Go to reset position. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/multiball_locks.md b/docs/code/api_reference/devices/multiball_locks.md new file mode 100644 index 0000000000..4b7d9f42c9 --- /dev/null +++ b/docs/code/api_reference/devices/multiball_locks.md @@ -0,0 +1,85 @@ + +# self.machine.multiball_locks.* + +class mpf.devices.multiball_lock.MultiballLock(*args, **kwargs) + +Bases: mpf.core.enable_disable_mixin.EnableDisableMixin, mpf.core.mode_device.ModeDevice + +Ball lock device which locks balls for a multiball. + +## Accessing multiball_locks in code + +The device collection which contains the multiball_locks in your machine is available via `self.machine.multiball_locks`. For example, to access one called “foo”, you would use `self.machine.multiball_locks.foo`. You can also access multiball_locks in dictionary form, e.g. `self.machine.multiball_locks['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Multiball_locks have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`disable()` + +Disable device. + +`enable() → None` + +Enable device. + +`enabled` + +Return true if enabled. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_reset_all_counts(**kwargs)` + +Event handler for reset_all_counts event. + +`event_reset_count_for_current_player(**kwargs)` + +Event handler for reset_count_for_current_player event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`is_virtually_full` + +Return true if lock is full. + +`locked_balls` + +Return the number of locked balls for the current player. + +`persist_enabled` + +Return if enabled is persisted. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + + Raise a ConfigFileError exception. + +`remaining_virtual_space_in_lock` + +Return the remaining capacity of the lock. + +`reset_all_counts()` + +Reset the locked balls for all players. + +`reset_count_for_current_player()` + +Reset the locked balls for the current player. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/multiballs.md b/docs/code/api_reference/devices/multiballs.md new file mode 100644 index 0000000000..95712803c0 --- /dev/null +++ b/docs/code/api_reference/devices/multiballs.md @@ -0,0 +1,97 @@ + +# self.machine.multiballs.* + +`class mpf.devices.multiball.Multiball(*args, **kwargs)` + +Bases: mpf.core.enable_disable_mixin.EnableDisableMixin, mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +Multiball device for MPF. + +## Accessing multiballs in code + +The device collection which contains the multiballs in your machine is available via `self.machine.multiballs`. For example, to access one called “foo”, you would use `self.machine.multiballs.foo`. You can also access multiballs in dictionary form, e.g. `self.machine.multiballs['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Multiballs have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_a_ball()` + +Add a ball if multiball has started. + +`disable()` + +Disable device. + +`enable() → None` + +Enable device. + +`enabled` + +Return true if enabled. + +`event_add_a_ball(**kwargs)` + +Event handler for add_a_ball event. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`event_start(**kwargs)` + +Event handler for start event. + +`event_start_or_add_a_ball(**kwargs)` + +Event handler for start_or_add_a_ball event. + +`event_stop(**kwargs)` + +Event handler for stop event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`persist_enabled` + +Return if enabled is persisted. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset the multiball and disable it. + +`start()` + +Start multiball. + +`start_or_add_a_ball()` + +Start multiball or add a ball if multiball has started. + +`stop()` + +Stop shoot again. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/p3_roc.md b/docs/code/api_reference/devices/p3_roc.md new file mode 100644 index 0000000000..ece0b12fbf --- /dev/null +++ b/docs/code/api_reference/devices/p3_roc.md @@ -0,0 +1,89 @@ + +# self.machine.hardware_platforms[‘p3_roc’] + +`class mpf.platforms.p3_roc.P3RocHardwarePlatform(machine)` + +Bases: mpf.platforms.p_roc_common.PROCBasePlatform, mpf.core.platform.I2cPlatform, mpf.core.platform.AccelerometerPlatform + +Platform class for the P3-ROC hardware controller. + +Parameters: + +* **machine** – The MachineController instance. + +## Accessing the p3_roc platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the p3_roc platform is available via `self.machine.hardware_platforms['p3_roc']`. + +## Methods & Attributes + +The p3_roc platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_accelerometer(number, config, callback)` + +Configure the accelerometer on the P3-ROC. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Create a P3-ROC driver. + +Typically drivers are coils or flashers, but for the P3-ROC this is also used for matrix-based lights. + +Parameters: + +* **config** – Dictionary of settings for the driver. +* **number** – Number of this driver. +* **platform_settings** – Platform specific settings + +Returns a reference to the PROCDriver object which is the actual object you can use to pulse(), patter(), enable(), etc. + +`configure_i2c(number: str)` + +Configure I2C device on P3-Roc. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure a P3-ROC switch. + +Parameters: + +* **number** – Number of this switch +* **config** – Dictionary of settings for the switch. +* **platform_config** – Platform specific settings. + +Returns: A configured switch object. + +`connect()` + +Connect to the P3-Roc. + +`get_hw_switch_states() → Dict[str, bool]` + +Read in and set the initial switch state. + +The P-ROC uses the following values for hw switch states: 1 - closed (debounced) 2 - open (debounced) 3 - closed (not debounced) 4 - open (not debounced) + +`get_info_string()` + +Dump infos about boards. + +`process_events(events)` + +Process events from the P3-Roc. + +`classmethod scale_accelerometer_to_g(raw_value)` + +Convert internal representation to g. + +`set_gpio(index, state)` + +Set GPIO state. + +`start()` + +Start GPIO poller. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/devices/p_roc.md b/docs/code/api_reference/devices/p_roc.md new file mode 100644 index 0000000000..d249d423cd --- /dev/null +++ b/docs/code/api_reference/devices/p_roc.md @@ -0,0 +1,73 @@ + +# self.machine.hardware_platforms[‘p_roc’] + +`class mpf.platforms.p_roc.PRocHardwarePlatform(machine)` + +Bases: mpf.platforms.p_roc_common.PROCBasePlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.SegmentDisplayPlatform + +Platform class for the P-ROC hardware controller. + +Parameters: + +* **machine** – The MachineController instance. + +## Accessing the p_roc platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the p_roc platform is available via `self.machine.hardware_platforms['p_roc']`. + +## Methods & Attributes + +The p_roc platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_dmd()` + +Configure a hardware DMD connected to a classic P-ROC. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Create a P-ROC driver. + +Typically drivers are coils or flashers, but for the P-ROC this is also used for matrix-based lights. + +Parameters: + +* **config** – Dictionary of settings for the driver. +* **number** – Number of this driver +* **platform_settings** – Platform specific setting for this driver. + +Returns a reference to the PROCDriver object which is the actual object you can use to pulse(), patter(), enable(), etc. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.interfaces.segment_display_platform_interface.SegmentDisplayPlatformInterface` + +Configure display. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure a P-ROC switch. + +Parameters: + +* **number** – String number of the switch to configure. +* **config** – SwitchConfig settings. +* **platform_config** – Platform specific settings. + +Returns: A configured switch object. + +`connect()` + +Connect to the P-Roc. + +`get_hw_switch_states() → Dict[str, bool]` + +Read in and set the initial switch state. + +The P-ROC uses the following values for hw switch states: 1 - closed (debounced) 2 - open (debounced) 3 - closed (not debounced) 4 - open (not debounced) + +`get_info_string()` + +Dump infos about boards. + +`process_events(events)` + +Process events from the P-Roc. + diff --git a/docs/code/api_reference/devices/pin2dmd.md b/docs/code/api_reference/devices/pin2dmd.md new file mode 100644 index 0000000000..204882fe5e --- /dev/null +++ b/docs/code/api_reference/devices/pin2dmd.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘pin2dmd’] + +`class mpf.platforms.pin2dmd.Pin2DmdHardwarePlatform(machine)` + +Bases: mpf.core.platform.RgbDmdPlatform + +PIN2DMD RGB DMD hardware. + +## Accessing the pin2dmd platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the pin2dmd platform is available via `self.machine.hardware_platforms['pin2dmd']`. + +## Methods & Attributes + +The pin2dmd platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_rgb_dmd(name: str)` + +Configure rgb dmd. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/devices/playfield_transfers.md b/docs/code/api_reference/devices/playfield_transfers.md new file mode 100644 index 0000000000..48b36b3d36 --- /dev/null +++ b/docs/code/api_reference/devices/playfield_transfers.md @@ -0,0 +1,35 @@ + +# self.machine.playfield_transfers.* + +`class mpf.devices.playfield_transfer.PlayfieldTransfer(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Device which move a ball from one playfield to another. + +## Accessing playfield_transfers in code + +The device collection which contains the playfield_transfers in your machine is available via `self.machine.playfield_transfers`. For example, to access one called “foo”, you would use `self.machine.playfield_transfers.foo`. You can also access playfield_transfers in dictionary form, e.g. `self.machine.playfield_transfers['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +`Playfield_transfers have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`event_transfer(**kwargs)` + +Event handler for transfer event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`transfer()` + +Transfer a ball to the target playfield. + diff --git a/docs/code/api_reference/devices/playfields.md b/docs/code/api_reference/devices/playfields.md new file mode 100644 index 0000000000..56e3323ded --- /dev/null +++ b/docs/code/api_reference/devices/playfields.md @@ -0,0 +1,141 @@ + +self.machine.playfields.* + +class mpf.devices.playfield.Playfield(*args, **kwargs) + +Bases: mpf.core.system_wide_device.SystemWideDevice + +One playfield in a pinball machine. + +## Accessing playfields in code + +The device collection which contains the playfields in your machine is available via `self.machine.playfields`. For example, to access one called “foo”, you would use `self.machine.playfields.foo`. You can also access playfields in dictionary form, e.g. `self.machine.playfields['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Playfields have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_ball(balls=1, source_device=None, player_controlled=False) → bool` + +Add live ball(s) to the playfield. + +Parameters: + +* **balls** – Integer of the number of balls you’d like to add. +* **source_device** – Optional ball device object you’d like to add the ball(s) from. +* **player_controlled** – Boolean which specifies whether this event is player controlled. (See not below for details) + +Returns True if it’s able to process the add_ball() request, False if it cannot. + +The source_device arg is included to give you an options for specifying the source of the ball(s) to be added. This argument is optional, so if you don’t supply them then MPF will use the default_source_device of this playfield. + +This method does not increase the game controller’s count of the number of balls in play. So if you want to add balls (like in a multiball scenario), you need to call this method along with self.machine.game.add_balls_in_play().) + +MPF tracks the number of balls in play separately from the actual balls on the playfield because there are numerous situations where the two counts are not the same. For example, if a ball is in a VUK while some animation is playing, there are no balls on the playfield but still one ball in play, or if the player has a two-ball multiball and they shoot them both into locks, there are still two balls in play even though there are no balls on the playfield. The opposite can also be true, like when the player tilts then there are still balls on the playfield but no balls in play. + +Explanation of the player_controlled parameter: + +Set player_controlled to True to indicate that MPF should wait for the player to eject the ball from the source_device rather than firing a coil. The logic works like this: + +If the source_device does not have an eject_coil defined, then it’s assumed that player_controlled is the only option. (e.g. this is a traditional plunger.) If the source_device does have an eject_coil defined, then there are two ways the eject could work. (1) there could be a “launch” button of some kind that’s used to fire the eject coil, or (2) the device could be the auto/manual combo style where there’s a mechanical plunger but also a coil which can eject the ball. + +If player_controlled is true and the device has an eject_coil, MPF will look for the player_controlled_eject_tag and eject the ball when a switch with that tag is activated. + +If there is no player_controlled_eject_tag, MPF assumes it’s a manual plunger and will wait for the ball to disappear from the device based on the device’s ball count decreasing. + +`add_incoming_ball(incoming_ball: mpf.devices.ball_device.incoming_balls_handler.IncomingBall)` + +Track an incoming ball. + +`add_missing_balls(balls)` + +Notify the playfield that it probably received a ball which went missing elsewhere. + +`ball_arrived()` + +Confirm first ball in queue. + +`ball_search` + +An instance of mpf.core.ball_search.BallSearch which handles ball search for this playfield. + +`balls` + +Return the number of balls on the playfield. + +`delay` + +An instance of mpf.core.delays.DelayManager which handles delays for this playfield. + +`event_ball_search_block(**kwargs)` + +Block ball search for this playfield. + +Blocking will disable ball search if it’s enabled or running, and will prevent ball search from enabling if it’s disabled until ball_search_resume() is called. + +`event_ball_search_disable(**kwargs)` + +Disable ball search for this playfield. + +If the ball search timer is running, it will stop and disable it. If an actual ball search process is running, it will stop. + +`event_ball_search_enable(**kwargs)` + +Enable ball search for this playfield. + +Note this does not start the ball search process, rather, it starts the timer running. + +`event_ball_search_unblock(**kwargs)` + +Unblock ball search for this playfield. + +This will check to see if there are balls on the playfield, and if so, enable ball search. + +`expected_ball_received()` + +Handle an expected ball. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`classmethod get_additional_ball_capacity()` + +Return the number of ball which can be added. + +Used to find out how many more balls this device can hold. Since this is the playfield device, this method always returns 999. + +Returns: 999 + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`classmethod is_playfield()` + +Return true since it is a playfield. + +`mark_playfield_active_from_device_action()` + +Mark playfield active because a device on the playfield detected activity. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove_incoming_ball(incoming_ball: mpf.devices.ball_device.incoming_balls_handler.IncomingBall)` + +Stop tracking an incoming ball. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`unexpected_ball_received()` + +Handle an unexpected ball. + +`static wait_for_ready_to_receive(source)` + +Playfield is always ready to receive. + diff --git a/docs/code/api_reference/devices/pololu_maestro.md b/docs/code/api_reference/devices/pololu_maestro.md new file mode 100644 index 0000000000..d2bab5772e --- /dev/null +++ b/docs/code/api_reference/devices/pololu_maestro.md @@ -0,0 +1,35 @@ + +# self.machine.hardware_platforms[‘pololu_maestro’] + +`class mpf.platforms.pololu_maestro.PololuMaestroHardwarePlatform(machine)` + +Bases: mpf.core.platform.ServoPlatform + +Supports the Pololu Maestro servo controllers via PySerial. + +Works with Micro Maestro 6, and Mini Maestro 12, 18, and 24. + +## Accessing the pololu_maestro platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the pololu_maestro platform is available via `self.machine.hardware_platforms['pololu_maestro'].` + +## Methods & Attributes + +`The pololu_maestro platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_servo(number: str)` + +Configure a servo device in platform. + +Parameters: + +* **number** – Number of the servo. + +`initialize()` + +Initialise platform. + +`stop()` + +Close serial. + diff --git a/docs/code/api_reference/devices/pololu_tic.md b/docs/code/api_reference/devices/pololu_tic.md new file mode 100644 index 0000000000..bc7242db12 --- /dev/null +++ b/docs/code/api_reference/devices/pololu_tic.md @@ -0,0 +1,34 @@ + +# self.machine.hardware_platforms[‘pololu_tic’] + +`class mpf.platforms.pololu.pololu_tic.PololuTICHardwarePlatform(machine)` + +Bases: mpf.core.platform.StepperPlatform + +Supports the Pololu TIC stepper drivers via ticcmd command line. + +## Accessing the pololu_tic platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the pololu_tic platform is available via `self.machine.hardware_platforms['pololu_tic']`. + +## Methods & Attributes + +The pololu_tic platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_stepper(number: str, config: dict) → mpf.platforms.pololu.pololu_tic.PololuTICStepper` + +Configure a smart stepper device in platform. + +Parameters: + +* **number** – Number of this stepper. +* **config (dict)** – Configuration of device + +`classmethod get_stepper_config_section()` + +Return config validator name. + +`stop()` + +De-energize the stepper and stop sending the command timeout refresh. + diff --git a/docs/code/api_reference/devices/psus.md b/docs/code/api_reference/devices/psus.md new file mode 100644 index 0000000000..14b8050654 --- /dev/null +++ b/docs/code/api_reference/devices/psus.md @@ -0,0 +1,33 @@ + +# self.machine.psus.* + +`class mpf.devices.power_supply_unit.PowerSupplyUnit(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a power supply in a pinball machine. + +## Accessing psus in code + +The device collection which contains the psus in your machine is available via `self.machine.psus`. For example, to access one called “foo”, you would use `self.machine.psus.foo`. You can also access psus in dictionary form, e.g. `self.machine.psus['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Psus have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_wait_time_for_pulse(pulse_ms, max_wait_ms) → int` + +Return a wait time for a pulse or 0. + +`notify_about_instant_pulse(pulse_ms)` + +Notify PSU about pulse. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/rgb_dmds.md b/docs/code/api_reference/devices/rgb_dmds.md new file mode 100644 index 0000000000..546ebf6434 --- /dev/null +++ b/docs/code/api_reference/devices/rgb_dmds.md @@ -0,0 +1,31 @@ +# self.machine.rgb_dmds.* + +`class mpf.devices.rgb_dmd.RgbDmd(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +A physical DMD. + +## Accessing rgb_dmds in code + +The device collection which contains the rgb_dmds in your machine is available via `self.machine.rgb_dmds`. For example, to access one called “foo”, you would use `self.machine.rgb_dmds.foo`. You can also access rgb_dmds in dictionary form, e.g. `self.machine.rgb_dmds['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Rgb_dmds have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +` format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +` raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +` update(data: bytes)` + +Update data on the dmd. + +Parameters: + +* **data** – bytes to send diff --git a/docs/code/api_reference/devices/rpi.md b/docs/code/api_reference/devices/rpi.md new file mode 100644 index 0000000000..af5b49ede4 --- /dev/null +++ b/docs/code/api_reference/devices/rpi.md @@ -0,0 +1,75 @@ + +# self.machine.hardware_platforms[‘rpi’] + +`class mpf.platforms.rpi.rpi.RaspberryPiHardwarePlatform(machine)` + +Bases: mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.ServoPlatform, mpf.core.platform.I2cPlatform + +Control the hardware of a Raspberry Pi. + +Works locally and remotely via network. + +## Accessing the rpi platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the rpi platform is available via `self.machine.hardware_platforms['rpi']`. + +## Methods & Attributes + +The rpi platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict) → mpf.platforms.interfaces.driver_platform_interface.DriverPlatformInterface` + +Configure an output on the Raspberry Pi. + +`configure_i2c(number: str)` + +Configure I2c device. + +`configure_servo(number: str) → mpf.platforms.interfaces.servo_platform_interface.ServoPlatformInterface` + +Configure a servo. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure a switch with pull up. + +`get_hw_switch_states()` + +Return current switch states. + +`initialize()` + +Initialise platform. + +`send_command(cmd)` + +Add a command to the command queue. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Raise exception. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Raise exception. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/devices/rpi_dmd.md b/docs/code/api_reference/devices/rpi_dmd.md new file mode 100644 index 0000000000..872fdd19c7 --- /dev/null +++ b/docs/code/api_reference/devices/rpi_dmd.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘rpi_dmd’] + +`class mpf.platforms.rpi_dmd.RpiDmdPlatform(machine)` + +Bases: mpf.core.platform.RgbDmdPlatform + +Raspberry Pi GPIO RGB DMD. + +## Accessing the rpi_dmd platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the rpi_dmd platform is available via `self.machine.hardware_platforms['rpi_dmd']`. + +## Methods & Attributes + +The rpi_dmd platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_rgb_dmd(name: str)` + +Configure rgb dmd. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/devices/score_queues.md b/docs/code/api_reference/devices/score_queues.md new file mode 100644 index 0000000000..6979fd58f2 --- /dev/null +++ b/docs/code/api_reference/devices/score_queues.md @@ -0,0 +1,34 @@ + +# self.machine.score_queues.* + +`class mpf.devices.score_queue.ScoreQueue(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Score queues for SS games. + +Add scores over time and play a lot of chimes. + +## Accessing score_queues in code + +The device collection which contains the score_queues in your machine is available via `self.machine.score_queues`. For example, to access one called “foo”, you would use `self.machine.score_queues.foo`. You can also access score_queues in dictionary form, e.g. `self.machine.score_queues['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Score_queues have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`score(value, **kwargs)` + +Score a value via the queue. + +`stop_device()` +Stop queue. + diff --git a/docs/code/api_reference/devices/score_reel_groups.md b/docs/code/api_reference/devices/score_reel_groups.md new file mode 100644 index 0000000000..40e25d0c7c --- /dev/null +++ b/docs/code/api_reference/devices/score_reel_groups.md @@ -0,0 +1,75 @@ + +# self.machine.score_reel_groups.* + +`class mpf.devices.score_reel_group.ScoreReelGroup(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a logical grouping of score reels in a pinball machine. + +Multiple individual ScoreReel object make up the individual digits of this group. This group also has support for the blank zero “inserts” that some machines use. This is a subclass of mpf.core.device.Device. + +## Accessing score_reel_groups in code + +The device collection which contains the score_reel_groups in your machine is available via `self.machine.score_reel_groups`. For example, to access one called “foo”, you would use `self.machine.score_reel_groups.foo`. You can also access score_reel_groups in dictionary form, e.g. `self.machine.score_reel_groups['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Score_reel_groups have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`classmethod chime(chime, **kwargs)` + +Pulse chime. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`int_to_reel_list(value)` + +Convert an integer to a list of integers that represent each positional digit in this ScoreReelGroup. + +The list returned is in reverse order. (See the example below.) + +The list returned is customized for this ScoreReelGroup both in terms of number of elements and values of None used to represent blank plastic zero inserts that are not controlled by a score reel unit. + +For example, if you have a 5-digit score reel group that has 4 phyiscial reels in the tens through ten-thousands position and a fake plastic “0” insert for the ones position, if you pass this method a value of 12300, it will return [None, 0, 3, 2, 1] + +This method will pad shorter ints with zeros, and it will chop off leading digits for ints that are too long. (For example, if you pass a value of 10000 to a ScoreReelGroup which only has 4 digits, the returns list would correspond to 0000, since your score reel unit has rolled over.) + +Parameters: + +* **value** – The interger value you’d like to convert. + +Returns a list containing the values for each corresponding score reel, with the lowest reel digit position in list position 0. + +`light(**kwargs)` + +Light up this ScoreReelGroup based on the ‘light_tag’ in its config. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`set_value(value)` + +Reset the score reel group to display the value passed. + +This method will “jump” the score reel group to display the value that’s passed as an it. (Note this “jump” technique means it will just move the reels as fast as it can, and nonsensical values might show up on the reel while the movement is in progress.) + +This method is used to “reset” a reel group to all zeros at the beginning of a game, and can also be used to reset a reel group that is confused or to switch a reel to the new player’s score if multiple players a sharing the same reel group. + +Note you can choose to pass either an integer representation of the value, or a value list. + +Parameters: + +* **value** – An integer value of what the new displayed value (i.e. score) should be. This is the default option if you only pass a single positional argument, e.g. set_value(2100). + +`unlight(**kwargs)` + +Turn off the lights for this ScoreReelGroup based on the ‘light_tag’ in its config. + +`wait_for_ready()` + +Return a future which will be done when all reels reached their destination. + diff --git a/docs/code/api_reference/devices/score_reels.md b/docs/code/api_reference/devices/score_reels.md new file mode 100644 index 0000000000..e35daaaa3d --- /dev/null +++ b/docs/code/api_reference/devices/score_reels.md @@ -0,0 +1,60 @@ + +# self.machine.score_reels.* + +`class mpf.devices.score_reel.ScoreReel(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents an individual electro-mechanical score reel in a pinball machine. + +Multiples reels of this class can be grouped together into ScoreReelGroups which collectively make up a display like “Player 1 Score” or “Player 2 card value”, etc. + +This device class is used for all types of mechanical number reels in a machine, including reels that have more than ten numbers and that can move in multiple directions (such as the credit reel). + +## Accessing score_reels in code + +The device collection which contains the score_reels in your machine is available via `self.machine.score_reels`. For example, to access one called “foo”, you would use `self.machine.score_reels.foo`. You can also access score_reels in dictionary form, e.g. `self.machine.score_reels['foo']`. You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Score_reels have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`check_hw_switches()` + +Check all the value switches for this score reel. + +This check only happens if self.ready is True. If the reel is not ready, it means another advance request has come in after the initial one. In that case then the subsequent advance will call this method again when after that advance is done. + +If this method finds an active switch, it sets self.physical_value to that. Otherwise it sets it to -999. It will also update self.assumed_value if it finds an active switch. Otherwise it leaves that value unchanged. + +This method is automatically called (via a delay) after the reel advances. The delay is based on the config value self.config[‘hw_confirm_time’]. + +TODO: What happens if there are multiple active switches? Currently it will return the highest one. Is that ok? + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`set_destination_value(value)` + +Return the integer value of the destination this reel is moving to. + +Parameters: + +* **value** – Destination value which this reel should try to reach. + +Returns: The value of the destination. If the current +`self.assumed_value` is -999, this method will always return -999 since it doesn’t know where the reel is and therefore doesn’t know what the destination value would be. + +`stop(**kwargs)` + +Stop device. + +`wait_for_ready()` + +Return a future for ready. + diff --git a/docs/code/api_reference/devices/segment_displays.md b/docs/code/api_reference/devices/segment_displays.md new file mode 100644 index 0000000000..bbbdda9992 --- /dev/null +++ b/docs/code/api_reference/devices/segment_displays.md @@ -0,0 +1,49 @@ + +self.machine.segment_displays.* + +`class mpf.devices.segment_display.SegmentDisplay(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +A physical segment display in a pinball machine. + +## Accessing segment_displays in code + +The device collection which contains the segment_displays in your machine is available via `self.machine.segment_displays`. For example, to access one called “foo”, you would use `self.machine.segment_displays.foo`. You can also access segment_displays in dictionary form, e.g. `self.machine.segment_displays['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Segment_displays have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_text(text: str, priority: int = 0, key: str = None) → None` + +Add text to display stack. + +This will replace texts with the same key. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove_text_by_key(key: str)` + +Remove entry from text stack. + +`set_flashing(flashing: bool)` + +Enable/Disable flashing. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/sequence_shots.md b/docs/code/api_reference/devices/sequence_shots.md new file mode 100644 index 0000000000..b6f2e03ca3 --- /dev/null +++ b/docs/code/api_reference/devices/sequence_shots.md @@ -0,0 +1,43 @@ + +# self.machine.sequence_shots.* + +`class mpf.devices.sequence_shot.SequenceShot(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +A device which represents a sequence shot. + +## Accessing sequence_shots in code + +The device collection which contains the sequence_shots in your machine is available via `self.machine.sequence_shots`. For example, to access one called “foo”, you would use `self.machine.sequence_shots.foo`. You can also access sequence_shots in dictionary form, e.g. `self.machine.sequence_shots['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Sequence_shots have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enable() → None` + +Enable handler. + +`event_cancel(**kwargs)` + +Event handler for cancel event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset_all_sequences()` + +Reset all sequences. + diff --git a/docs/code/api_reference/devices/sequences.md b/docs/code/api_reference/devices/sequences.md new file mode 100644 index 0000000000..8739f711bf --- /dev/null +++ b/docs/code/api_reference/devices/sequences.md @@ -0,0 +1,105 @@ + +# self.machine.sequences.* + +`class mpf.devices.logic_blocks.Sequence(*args, **kwargs)` + +Bases: mpf.devices.logic_blocks.LogicBlock + +A type of LogicBlock which tracks many different events (steps) towards a goal. + +The steps have to happen in order. + +## Accessing sequences in code + +The device collection which contains the sequences in your machine is available via `self.machine.sequences`. For example, to access one called “foo”, you would use `self.machine.sequences.foo`. You can also access sequences in dictionary form, e.g. `self.machine.sequences['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Sequences have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`complete()` + +Mark this logic block as complete. + +Posts the ‘events_when_complete’ events and optionally restarts this logic block or disables it, depending on this block’s configuration settings. + +`completed` + +Return if completed. + +`disable()` + +Disable this logic block. + +Automatically called when one of the disable_event events is posted. Can also manually be called. + +`enable()` + +Enable this logic block. + +Automatically called when one of the enable_event events is posted. Can also manually be called. + +`enabled` + +Return if enabled. + +`event_disable(**kwargs)` + +Event handler for disable event. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`event_restart(**kwargs)` + +Event handler for restart event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`get_start_value() → int` + +Return start step. + +`hit(step: int = None, **kwargs)` + +Increase the hit progress towards completion. + +Automatically called when one of the count_events is posted. Can also manually be called. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset the progress towards completion of this logic block. + +Automatically called when one of the reset_event events is called. Can also be manually called. + +`restart()` + +Restart this logic block by calling reset() and enable(). + +Automatically called when one of the restart_event events is called. Can also be manually called. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`value` + +Return value or None if that is currently not possible. + diff --git a/docs/code/api_reference/devices/servos.md b/docs/code/api_reference/devices/servos.md new file mode 100644 index 0000000000..21d2d193f0 --- /dev/null +++ b/docs/code/api_reference/devices/servos.md @@ -0,0 +1,57 @@ + +# self.machine.servos.* + +`class mpf.devices.servo.Servo(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a servo in a pinball machine. + +Args: Same as the Device parent class. + +## Accessing servos in code + +The device collection which contains the servos in your machine is available via `self.machine.servos`. For example, to access one called “foo”, you would use `self.machine.servos.foo`. You can also access servos in dictionary form, e.g. `self.machine.servos['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Servos have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`go_to_position(position)` + +Move servo to position. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Go to reset position. + +`set_acceleration_limit(acceleration_limit)` + +Set acceleration parameter. + +`set_speed_limit(speed_limit)` + +Set speed parameter. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/shot_groups.md b/docs/code/api_reference/devices/shot_groups.md new file mode 100644 index 0000000000..1e6fa3eec8 --- /dev/null +++ b/docs/code/api_reference/devices/shot_groups.md @@ -0,0 +1,133 @@ + +# self.machine.shot_groups.* + +`class mpf.devices.shot_group.ShotGroup(*args, **kwargs)` + +Bases: mpf.core.mode_device.ModeDevice + +Represents a group of shots in a pinball machine by grouping together multiple Shot class devices. + +This is used so you get get “group-level” functionality, like shot rotation, shot group completion, etc. This would be used for a group of rollover lanes, a bank of standups, etc. + +## Accessing shot_groups in code + +The device collection which contains the shot_groups in your machine is available via `self.machine.shot_groups`. For example, to access one called “foo”, you would use `self.machine.shot_groups.foo`. You can also access shot_groups in dictionary form, e.g. `self.machine.shot_groups['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Shot_groups have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`common_state` + +Return common state if all shots in this group are in the same state. + +Will return None otherwise. + +`disable()` + +Disable all member shots. + +`disable_rotation()` + +Disable shot rotation. + +If disabled, rotation events do not actually rotate the shots. + +`enable()` + +Enable all member shots. + +`enable_rotation()` + +Enable shot rotation. + +If disabled, rotation events do not actually rotate the shots. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_disable_rotation(**kwargs)` + +Handle disable rotation control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_enable_rotation(**kwargs)` + +Handle enable_rotation control event. + +`event_reset(**kwargs)` + +Handle reset control event. + +`event_restart(**kwargs)` + +Handle restart control event. + +`event_rotate(direction=None, **kwargs)` + +Handle rotate control event. + +`event_rotate_left(**kwargs)` + +Handle rotate left control event. + +`event_rotate_right(**kwargs)` + +Handle rotate right control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset all member shots. + +`restart()` + +Restart all member shots. + +`rotate(direction=None)` + +Rotate (or “shift”) the state of all the shots in this group. + +This is used for things like lane change, where hitting the flipper button shifts all the states of the shots in the group to the left or right. + +This method actually transfers the current state of each shot profile to the left or the right, and the shot on the end rolls over to the taret on the other end. + +Parameters: + +* **direction** – String that specifies whether the rotation direction is to the left or right. Values are ‘right’ or ‘left’. Default of None will cause the shot group to rotate in the direction as specified by the rotation_pattern. + +Note that this shot group must, and rotation_events for this shot group, must both be enabled for the rotation events to work. + +`rotate_left()` + +Rotate the state of the shots to the left. + +This method is the same as calling rotate(‘left’) + +`rotate_right()` + +Rotate the state of the shots to the right. + +This method is the same as calling rotate(‘right’) + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/shot_profiles.md b/docs/code/api_reference/devices/shot_profiles.md new file mode 100644 index 0000000000..210ba297de --- /dev/null +++ b/docs/code/api_reference/devices/shot_profiles.md @@ -0,0 +1,35 @@ + +# self.machine.shot_profiles.* + +`class mpf.devices.shot_profile.ShotProfile(machine: mpf.core.machine.MachineController, name: str)` + +Bases: mpf.core.mode_device.ModeDevice, mpf.core.system_wide_device.SystemWideDevice + +A shot profile. + +## Accessing shot_profiles in code + +The device collection which contains the shot_profiles in your machine is available via `self.machine.shot_profiles`. For example, to access one called “foo”, you would use `self.machine.shot_profiles.foo`. You can also access shot_profiles in dictionary form, e.g. `self.machine.shot_profiles['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Shot_profiles have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enable() → None` + +Enable handler. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/shots.md b/docs/code/api_reference/devices/shots.md new file mode 100644 index 0000000000..b0590ede1e --- /dev/null +++ b/docs/code/api_reference/devices/shots.md @@ -0,0 +1,138 @@ + +# self.machine.shots.* + +`class mpf.devices.shot.Shot(*args, **kwargs)` + +Bases: mpf.core.enable_disable_mixin.EnableDisableMixin, mpf.core.mode_device.ModeDevice + +A device which represents a generic shot. + +## Accessing shots in code + +The device collection which contains the shots in your machine is available via `self.machine.shots`. For example, to access one called “foo”, you would use `self.machine.shots.foo`. You can also access shots in dictionary form, e.g. `self.machine.shots['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Shots have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`active_sequences` + +(id, current_position_index, next_switch) +Type: List of tuples + +`advance(force=False) → bool` + +Advance a shot profile forward. + +If this profile is at the last step and configured to loop, it will roll over to the first step. If this profile is at the last step and not configured to loop, this method has no effect. + +`can_rotate` + +Return if the shot can be rotated according to its profile. + +`disable()` + +Disable device. + +`enable() → None` + +Enable device. + +`enabled` + +Return true if enabled. + +`event_advance(force=False, **kwargs)` + +Handle advance control event. + +`event_disable(**kwargs)` + +Handle disable control event. + +`event_enable(**kwargs)` + +Handle enable control event. + +`event_hit(**kwargs)` + +Handle hit control event. + +`event_reset(**kwargs)` + +Handle reset control event. + +`event_restart(**kwargs)` + +Handle restart control event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`hit() → bool` + +Advance the currently-active shot profile. + +Note that the shot must be enabled in order for this hit to be processed. + +Returns true if the shot was enabled or false if the hit has been ignored. + +`jump(state, force=True, force_show=False)` + +Jump to a certain state in the active shot profile. + +Parameters: + +* **state** – int of the state number you want to jump to. Note that states are zero-based, so the first state is 0. +* **force** – if true, will jump even if the shot is disabled +* **force_show** – if true, will update the profile show even if the jumped state index is the same as before the jump + +`monitor_enabled = False` + +Class attribute which specifies whether any monitors have been registered to track shots. + +`persist_enabled` + +Return if enabled is persisted. + +`profile` + +Return profile. + +`profile_name` + +Return profile name. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Reset the shot profile for the passed mode back to the first state (State 0) and reset all sequences. + +`restart()` + +Restart the shot profile by calling reset() and enable(). + +Automatically called when one fo the restart_events is called. + +`state` + +Return current state index. + +`state_name` + +Return current state name. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/show_queues.md b/docs/code/api_reference/devices/show_queues.md new file mode 100644 index 0000000000..48275c0120 --- /dev/null +++ b/docs/code/api_reference/devices/show_queues.md @@ -0,0 +1,31 @@ + +# self.machine.show_queues.* + +`class mpf.devices.show_queue.ShowQueue(machine, name)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents a show queue. + +## Accessing show_queues in code + +The device collection which contains the show_queues in your machine is available via `self.machine.show_queues`. For example, to access one called “foo”, you would use `self.machine.show_queues.foo`. You can also access show_queues in dictionary form, e.g. `self.machine.show_queues['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Show_queues have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enqueue_show(show_config: mpf.assets.show.ShowConfig, start_step: int)` + +Add a show to the end of the queue. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + diff --git a/docs/code/api_reference/devices/smart_virtual.md b/docs/code/api_reference/devices/smart_virtual.md new file mode 100644 index 0000000000..7fa2a123cc --- /dev/null +++ b/docs/code/api_reference/devices/smart_virtual.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘smart_virtual’] + +`class mpf.platforms.smart_virtual.SmartVirtualHardwarePlatform(machine)` + +Bases: mpf.platforms.virtual.VirtualHardwarePlatform + +Base class for the smart_virtual hardware platform. + +## Accessing the smart_virtual platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the smart_virtual platform is available via `self.machine.hardware_platforms['smart_virtual']`. + +## Methods & Attributes + +The smart_virtual platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_ball_to_device(device: mpf.devices.ball_device.ball_device.BallDevice)` + +Add ball to device. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure driver. + +`start()` + +Initialise platform when all devices are ready. + diff --git a/docs/code/api_reference/devices/smartmatrix.md b/docs/code/api_reference/devices/smartmatrix.md new file mode 100644 index 0000000000..3c0f2129c7 --- /dev/null +++ b/docs/code/api_reference/devices/smartmatrix.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘smartmatrix’] + +`class mpf.platforms.smartmatrix.SmartMatrixHardwarePlatform(machine)` + +Bases: mpf.core.platform.RgbDmdPlatform + +SmartMatrix RGB DMD. + +## Accessing the smartmatrix platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the smartmatrix platform is available via `self.machine.hardware_platforms['smartmatrix']`. + +## Methods & Attributes + +The smartmatrix platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_rgb_dmd(name: str)` + +Configure rgb dmd. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/devices/smbus2.md b/docs/code/api_reference/devices/smbus2.md new file mode 100644 index 0000000000..c40bbeb7a5 --- /dev/null +++ b/docs/code/api_reference/devices/smbus2.md @@ -0,0 +1,25 @@ + +# self.machine.hardware_platforms[‘smbus2’] + +`class mpf.platforms.smbus2.Smbus2(machine)` + +Bases: mpf.core.platform.I2cPlatform + +I2C platform which uses the smbus interface on linux via the smbus2 python extension. + +## Accessing the smbus2 platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the smbus2 platform is available via `self.machine.hardware_platforms['smbus2']`. + +## Methods & Attributes + +The smbus2 platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_i2c(number: str) → mpf.platforms.smbus2.Smbus2I2cDevice` + +Configure device on smbus2. + +`initialize()` + +Check if smbus2 extension has been imported. + diff --git a/docs/code/api_reference/devices/snux.md b/docs/code/api_reference/devices/snux.md new file mode 100644 index 0000000000..90a5af9792 --- /dev/null +++ b/docs/code/api_reference/devices/snux.md @@ -0,0 +1,17 @@ + +# self.machine.hardware_platforms[‘snux’] + +`class mpf.platforms.snux.SnuxHardwarePlatform(machine: mpf.core.machine.MachineController)` + +Bases: mpf.platforms.system11.System11OverlayPlatform + +Overlay platform for the snux hardware board. + +## Accessing the snux platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the snux platform is available via `self.machine.hardware_platforms['snux']`. + +## Methods & Attributes + +The snux platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + diff --git a/docs/code/api_reference/devices/spi_bit_bang.md b/docs/code/api_reference/devices/spi_bit_bang.md new file mode 100644 index 0000000000..13a05b7f09 --- /dev/null +++ b/docs/code/api_reference/devices/spi_bit_bang.md @@ -0,0 +1,35 @@ + +# self.machine.hardware_platforms[‘spi_bit_bang’] + +`class mpf.platforms.spi_bit_bang.SpiBitBangPlatform(machine)` + +Bases: mpf.core.platform.SwitchPlatform + +Platform which reads switch via SPI using bit banging. + +## Accessing the spi_bit_bang platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the spi_bit_bang platform is available via `self.machine.hardware_platforms['spi_bit_bang']`. + +## Methods & Attributes + +The spi_bit_bang platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure switch. + +`get_hw_switch_states()` + +Read initial hardware state. + +This will always be false for all inputs on those switches. + +`initialize()` + +Register handler for late init. + +`read_spi(bits)` + +Read from SPI. + diff --git a/docs/code/api_reference/devices/spike.md b/docs/code/api_reference/devices/spike.md new file mode 100644 index 0000000000..9d49af64d4 --- /dev/null +++ b/docs/code/api_reference/devices/spike.md @@ -0,0 +1,119 @@ + +# self.machine.hardware_platforms[‘spike’] + +class mpf.platforms.spike.spike.SpikePlatform(machine) + +Bases: mpf.core.platform.SwitchPlatform, mpf.core.platform.LightsPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.StepperPlatform + +Stern Spike Platform. + +## Accessing the spike platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the spike platform is available via `self.machine.hardware_platforms['spike']`. + +## Methods & Attributes + +The spike platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch, coil)` + +Disable hardware rule for this coil. + +`configure_dmd()` + +Configure a DMD. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure a driver on Stern Spike. + +`configure_light(number, subtype, platform_settings) → Union[mpf.platforms.spike.spike.SpikeLight, mpf.platforms.spike.spike.SpikeBacklight]` + +Configure a light on Stern Spike. + +`configure_stepper(number: str, config: dict) → mpf.platforms.interfaces.stepper_platform_interface.StepperPlatformInterface` + +Configure a stepper in Spike. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure switch on Stern Spike. + +`get_hw_switch_states()` + +Return current switch states. + +`classmethod get_stepper_config_section()` + +Return config validator name. + +`classmethod get_switch_config_section()` + +Return switch config section. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Return a single light. + +`send_cmd_and_wait_for_response(node, cmd, data, response_len) → Optional[bytearray]` + +Send cmd and wait for response. + +`send_cmd_async(node, cmd, data)` + +Send cmd which does not require a response. + +`send_cmd_raw(data, wait_ms=0)` + +Send raw command. + +`send_cmd_raw_async(data, wait_ms=0)` + +Send raw cmd which does not require a response. + +`send_cmd_sync(node, cmd, data)` + +Send cmd which does not require a response. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and release rule to driver. + +Used for high-power coil on single-wound flippers. Example from GoT: Node: 8 Command CoilSetReflex (0x41) Params: 0x00 0xff 0x33 0x00 0x1e 0x28 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x42 0x00 0x00 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x05 0x06 0x00 Len: 36 + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and enable and release rule on driver. + +Used for single coil flippers. Examples from WWE: Dual-wound flipper hold coil: Type: 8 Cmd: 65 Node: 8 Msg: 0x02 0xff 0x46 0x01 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3a 0x00 0x42 0x40 0x00 0x00 0x01 0x00 Len: 25 + +Ring Slings (different flags): Type: 8 Cmd: 65 Node: 10 Msg: 0x00 0xff 0x19 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x4a 0x40 0x00 0x00 0x06 0x05 Len: 25 + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and release rule to driver. + +Used for high-power coil on dual-wound flippers. Example from WWE: Type: 8 Cmd: 65 Node: 8 Msg: 0x00 0xff 0x33 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x42 0x40 0x00 0x02 0x06 0x00 Len: 25 + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and release rule to driver. + +I believe that param2 == 1 means that it will cancel the pulse when the switch is released. + +Used for high-power coils on dual-wound flippers. Example from WWE: Type: 8 Cmd: 65 Node: 8 Msg: 0x03 0xff 0x46 0x01 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x43 0x40 0x00 0x00 0x01 0x00 Len: 25 + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit rule on driver. + +This is mostly used for popbumpers. Example from WWE: Type: 8 Cmd: 65 Node: 9 Msg: 0x00 0xa6 0x28 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x14 0x00 0x00 0x00 0x38 0x00 0x40 0x00 0x00 0x00 0x00 0x00 Len: 25 + +`stop()` + +Stop hardware and close connections. + diff --git a/docs/code/api_reference/devices/state_machines.md b/docs/code/api_reference/devices/state_machines.md new file mode 100644 index 0000000000..7ccccbd538 --- /dev/null +++ b/docs/code/api_reference/devices/state_machines.md @@ -0,0 +1,47 @@ + +# self.machine.state_machines.* + +`class mpf.devices.state_machine.StateMachine(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +A generic state machine. + +## Accessing state_machines in code + +The device collection which contains the state_machines in your machine is available via `self.machine.state_machines`. For example, to access one called “foo”, you would use `self.machine.state_machines.foo`. You can also access state_machines in dictionary form, e.g. `self.machine.state_machines['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +State_machines have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enable() → None` + +Enable handler. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`state` + +Return the current state. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/step_stick.md b/docs/code/api_reference/devices/step_stick.md new file mode 100644 index 0000000000..c96084a547 --- /dev/null +++ b/docs/code/api_reference/devices/step_stick.md @@ -0,0 +1,25 @@ + +# self.machine.hardware_platforms[‘step_stick’] + +`class mpf.platforms.step_stick.StepStickDigitalOutputPlatform(machine)` + +Bases: mpf.core.platform.StepperPlatform + +Drive a stepper using a StepStick controller on a digital output. + +## Accessing the step_stick platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the step_stick platform is available via `self.machine.hardware_platforms['step_stick']`. + +## Methods & Attributes + +The step_stick platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_stepper(number: str, config: dict) → mpf.platforms.interfaces.stepper_platform_interface.StepperPlatformInterface` + +Configure a stepper driven by StepStick on a digital output. + +`classmethod get_stepper_config_section()` + +Return config section. + diff --git a/docs/code/api_reference/devices/steppers.md b/docs/code/api_reference/devices/steppers.md new file mode 100644 index 0000000000..57890942a7 --- /dev/null +++ b/docs/code/api_reference/devices/steppers.md @@ -0,0 +1,57 @@ + +# self.machine.steppers.* + +`class mpf.devices.stepper.Stepper(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice + +Represents an stepper motor based axis in a pinball machine. + +Args: Same as the Device parent class. + +## Accessing steppers in code + +The device collection which contains the steppers in your machine is available via `self.machine.steppers`. For example, to access one called “foo”, you would use `self.machine.steppers.foo`. You can also access steppers in dictionary form, e.g. `self.machine.steppers['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Steppers have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`event_move_to_position(position=None, **kwargs)` + +Event handler for move_to_position event. + +`event_reset(**kwargs)` + +Event handler for reset event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`move_to_position(position)` + +Move stepper to a position. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset()` + +Move to reset position. + +`stop()` + +Stop motor. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/switches.md b/docs/code/api_reference/devices/switches.md new file mode 100644 index 0000000000..412577e8c2 --- /dev/null +++ b/docs/code/api_reference/devices/switches.md @@ -0,0 +1,85 @@ + +# self.machine.switches.* + +`class mpf.devices.switch.Switch(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.devices.device_mixins.DevicePositionMixin + +A switch in a pinball machine. + +## Accessing switches in code + +The device collection which contains the switches in your machine is available via `self.machine.switches`. For example, to access one called “foo”, you would use `self.machine.switches.foo`. You can also access switches in dictionary form, e.g. `self.machine.switches['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Switches have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_handler(callback, state=1, ms=0, return_info=False, callback_kwargs=None)` + +Add switch handler (callback) for this switch which is called when this switch state changes. + +Note that this method just calls the Switch Controller’s add_switch_handler() method behind the scenes. + +Parameters: + +* **callback** – A callable method that will be called when the switch state changes. +* **state** – The state that the switch which change into which triggers the callback to be called. Values are 0 or 1, with 0 meaning the switch changed to inactive, and 1 meaning the switch changed to an active state. +* **ms** – How many milliseconds the switch needs to be in the new state before the callback is called. Default is 0 which means that the callback will be called immediately. You can use this setting as a form of software debounce, as the switch needs to be in the state consistently before the callback is called. +* **return_info** – If True, the switch controller will pass the parameters of the switch handler as arguments to the callback, including switch_name, state, and ms. +* **callback_kwargs** – Additional kwargs that will be passed with the callback. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_ms_since_last_change(current_time=None) → int` + +Get ms since last change. + +Will use the current time from clock if you do not pass it. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`hw_state` + +The physical hardware state of the switch. 1 = active, 0 = inactive. This is what the actual hardware is reporting and does not consider whether a switch is NC or NO. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove_handler(callback, state=1, ms=0)` + +Remove switch handler for this switch. + +`state` + +The logical state of a switch. 1 = active, 0 = inactive. This takes into consideration the NC or NO settings for the switch. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`x` + +Get the X value from the config. + +Returns the devices x position from config + +`y` + +Get the Y value from the config. + +Returns the devices y position from config + +`z` + +Get the Z value from the config. + +Returns the devices z position from config + diff --git a/docs/code/api_reference/devices/system11.md b/docs/code/api_reference/devices/system11.md new file mode 100644 index 0000000000..06af5b97e9 --- /dev/null +++ b/docs/code/api_reference/devices/system11.md @@ -0,0 +1,116 @@ + +# self.machine.hardware_platforms[‘system11’] + +`class mpf.platforms.system11.System11OverlayPlatform(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.platform.DriverPlatform, mpf.core.platform.SwitchPlatform + +Overlay platform to drive system11 machines using a WPC controller. + +## Accessing the system11 platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the system11 platform is available via `self.machine.hardware_platforms['system11']`. + +## Methods & Attributes + +The system11 platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`a_side_active` + +Return if A side cannot be switches off right away. + +`a_side_busy` + +Return if A side cannot be switches off right away. + +`c_side_active` + +Return if C side cannot be switches off right away. + +`c_side_busy` + +Return if C side cannot be switches off right away. + +`clear_hw_rule(switch, coil)` + +Clear a rule for a driver on the system11 overlay. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure a driver on the system11 overlay. + +Parameters: + +* **config** – Driver config dict +* **number** – Number of the driver. +* **platform_settings** – Platform specific config. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure switch on system11 overlay. + +`driver_action(driver, pulse_settings: Optional[mpf.platforms.interfaces.driver_platform_interface.PulseSettings], hold_settings: Optional[mpf.platforms.interfaces.driver_platform_interface.HoldSettings], side: str)` + +Add a driver action for a switched driver to the queue (for either the A-side or C-side queue). + +Parameters: + +* **driver** – A reference to the original platform class Driver instance. +* **pulse_settings** – Settings for the pulse or None +* **hold_settings** – Settings for hold or None +* **side** – Whatever the driver is on A or C side. + +This action will be serviced immediately if it can, or ASAP otherwise. + +`get_hw_switch_states()` + +Get initial hardware state. + +`initialize()` + +Automatically called by the Platform class after all the core modules are loaded. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch, coil)` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_and_release_rule(enable_switch, coil)` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_rule(enable_switch, coil)` + +Configure a rule on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`stop()` + +Stop the overlay. Nothing to do here because stop is also called on parent platform. + +`tick()` + +System11 main loop. + +Called based on the timer_tick event. + +`validate_coil_section(driver, config)` + +Validate coil config for platform. + diff --git a/docs/code/api_reference/devices/timed_switches.md b/docs/code/api_reference/devices/timed_switches.md new file mode 100644 index 0000000000..a7c846fe03 --- /dev/null +++ b/docs/code/api_reference/devices/timed_switches.md @@ -0,0 +1,43 @@ + +# self.machine.timed_switches.* + +`class mpf.devices.timed_switch.TimedSwitch(*args, **kwargs)` + +Bases: mpf.core.system_wide_device.SystemWideDevice, mpf.core.mode_device.ModeDevice + +Timed Switch device. + +## Accessing timed_switches in code + +The device collection which contains the timed_switches in your machine is available via `self.machine.timed_switches`. For example, to access one called “foo”, you would use `self.machine.timed_switches.foo`. You can also access timed_switches in dictionary form, e.g. `self.machine.timed_switches['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Timed_switches have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`enable() → None` + +Enable handler. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + diff --git a/docs/code/api_reference/devices/timers.md b/docs/code/api_reference/devices/timers.md new file mode 100644 index 0000000000..646bb8c6df --- /dev/null +++ b/docs/code/api_reference/devices/timers.md @@ -0,0 +1,150 @@ +# self.machine.timers.* + +`class mpf.devices.timer.Timer(*args, **kwargs)` + +Bases: mpf.core.mode_device.ModeDevice + +Parent class for a mode timer. + +Parameters: + +* **machine** – The main MPF MachineController object. +* **name** – The string name of this timer. + +## Accessing timers in code + +The device collection which contains the timers in your machine is available via `self.machine.timers`. For example, to access one called “foo”, you would use `self.machine.timers.foo`. You can also access timers in dictionary form, e.g. `self.machine.timers['foo']`. + +You can also get devices by tag or hardware number. See the DeviceCollection documentation for details. + +## Methods & Attributes + +Timers have the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add(timer_value, **kwargs)` + +Add ticks to this timer. + +Parameters: + +* **timer_value** – The number of ticks you want to add to this timer’s current value. +* **kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`change_tick_interval(change=0.0, **kwargs)` + +Change the interval for each “tick” of this timer. + +Parameters: + +* **change** – Float or int of the change you want to make to this timer’s tick rate. Note this value is multiplied by the current tick interval: >1 will increase the tick interval (slow the timer) and <1 will decrease the tick interval (accelerate the timer). To set an absolute value, use the set_tick_interval() method. +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`enable() → None` + +Enable handler. + +`event_enable(**kwargs)` + +Event handler for enable event. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_placeholder_value(item)` + +Get the value of a placeholder. + +`jump(timer_value, **kwargs)` + +Set the current amount of time of this timer. + +This value is expressed in “ticks” since the interval per tick can be something other than 1 second). + +Parameters: + +* **timer_value** – Integer of the current value you want this timer to be. +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`pause(timer_value=0, **kwargs)` + +Pause the timer and posts the ‘timer__paused’ event. + +Parameters: + +* **timer_value** – How many seconds you want to pause the timer for. Note that this pause time is real-world seconds and does not take into consideration this timer’s tick interval. +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset(**kwargs)` + +Reset this timer based to the starting value that’s already been configured. + +Does not start or stop the timer. + +Parameters: + +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`restart(**kwargs)` + +Restart the timer by resetting it and then starting it. + +Essentially this is just a reset() then a start(). + +Parameters: + +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`set_tick_interval(timer_value, **kwargs)` + +Set the number of seconds between ticks for this timer. + +This is an absolute setting. To apply a change to the current value, use the change_tick_interval() method. + +Parameters: + +* **timer_value** – The new number of seconds between each tick of this timer. This value should always be positive. +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`start(**kwargs)` + +Start this timer based on the starting value that’s already been configured. + +Use jump() if you want to set the starting time value. + +Parameters: + +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`stop(**kwargs)` + +Stop the timer and posts the ‘timer__stopped’ event. +Parameters: **kwargs – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`subscribe_attribute(item, machine)` + +Subscribe to an attribute. + +`subtract(timer_value, **kwargs)` + +Subtract ticks from this timer. + +Parameters: + +* **timer_value** – The number of ticks you want to subtract from this timer’s current value. +* ****kwargs** – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. + +`ticks` + +Return ticks. + +`timer_complete(**kwargs)` + +Automatically called when this timer completes. + +Posts the ‘timer__complete’ event. Can be manually called to mark this timer as complete. +Parameters: **kwargs – Not used in this method. Only exists since this method is often registered as an event handler which may contain additional keyword arguments. diff --git a/docs/code/api_reference/devices/trinamics_steprocker.md b/docs/code/api_reference/devices/trinamics_steprocker.md new file mode 100644 index 0000000000..7f02fca508 --- /dev/null +++ b/docs/code/api_reference/devices/trinamics_steprocker.md @@ -0,0 +1,39 @@ + +# self.machine.hardware_platforms[‘trinamics_steprocker’] + +`class mpf.platforms.trinamics_steprocker.TrinamicsStepRocker(machine)` + +Bases: mpf.core.platform.StepperPlatform + +Supports the Trinamics Step Rocker via PySerial. + +Works with Trinamics Step Rocker. TBD other ‘TMCL’ based steppers eval boards + +## Accessing the trinamics_steprocker platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the trinamics_steprocker platform is available via `self.machine.hardware_platforms['trinamics_steprocker']`. + +## Methods & Attributes + +The trinamics_steprocker platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_stepper(number: str, config: dict) → mpf.platforms.trinamics_steprocker.TrinamicsTMCLStepper` + +Configure a smart stepper device in platform. + +Parameters: + +* **number** – Number of the stepper. +* **config (dict)** – Configuration of device + +`classmethod get_stepper_config_section()` + +Return config validator name. + +`initialize()` + +Initialise trinamics steprocker platform. + +`stop()` + +Close serial. diff --git a/docs/code/api_reference/devices/virtual.md b/docs/code/api_reference/devices/virtual.md new file mode 100644 index 0000000000..e4c4551083 --- /dev/null +++ b/docs/code/api_reference/devices/virtual.md @@ -0,0 +1,113 @@ + +# self.machine.hardware_platforms[‘virtual’] + +`class mpf.platforms.virtual.VirtualHardwarePlatform(machine)` + +Bases: mpf.core.platform.AccelerometerPlatform, mpf.core.platform.I2cPlatform, mpf.core.platform.ServoPlatform, mpf.core.platform.LightsPlatform, mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.RgbDmdPlatform, mpf.core.platform.SegmentDisplayPlatform, mpf.core.platform.StepperPlatform, mpf.core.platform.HardwareSoundPlatform + +Base class for the virtual hardware platform. + +## Accessing the virtual platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the virtual platform is available via `self.machine.hardware_platforms['virtual']`. + +## Methods & Attributes + +The virtual platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch, coil)` + +Clear hw rule. + +`configure_accelerometer(number, config, callback)` + +Configure accelerometer. + +`configure_dmd()` + +Configure DMD. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure driver. + +`configure_hardware_sound_system() → mpf.platforms.interfaces.hardware_sound_platform_interface.HardwareSoundPlatformInterface` + +Configure virtual hardware sound system. + +`configure_i2c(number: str) → mpf.platforms.interfaces.i2c_platform_interface.I2cPlatformInterface` + +Configure virtual i2c device. + +`configure_light(number, subtype, platform_settings)` + +Configure light channel. + +`configure_rgb_dmd(name: str)` + +Configure DMD. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.interfaces.segment_display_platform_interface.SegmentDisplayPlatformInterface` + +Configure segment display. + +`configure_servo(number: str)` + +Configure a servo device in platform. + +`configure_stepper(number: str, config: dict)` + +Configure a smart stepper / axis device in platform. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure switch. + +`get_hw_switch_states()` + +Return hw switch states. + +`initialize() → None` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse channel str to a list of channels. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set rule. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch, coil)` + +Set rule. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set rule. + +`set_pulse_on_hit_and_release_rule(enable_switch, coil)` + +Set rule. + +`set_pulse_on_hit_rule(enable_switch, coil)` + +Set rule. + +`stop()` + +Stop platform. + +`validate_coil_section(driver, config)` + +Validate coil sections. + +`validate_stepper_section(stepper, config)` + +Validate stepper sections. + +`validate_switch_section(switch, config)` + +Validate switch sections. + diff --git a/docs/code/api_reference/devices/virtual_pinball.md b/docs/code/api_reference/devices/virtual_pinball.md new file mode 100644 index 0000000000..566dfe92fe --- /dev/null +++ b/docs/code/api_reference/devices/virtual_pinball.md @@ -0,0 +1,125 @@ + +# self.machine.hardware_platforms[‘virtual_pinball’] + +`class mpf.platforms.virtual_pinball.virtual_pinball.VirtualPinballPlatform(machine)` + +Bases: mpf.core.platform.LightsPlatform, mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform + +VPX platform. + +## Accessing the virtual_pinball platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the virtual_pinball platform is available via `self.machine.hardware_platforms['virtual_pinball']`. + +## Methods & Attributes + +The virtual_pinball platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Clear hw rule. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict) → mpf.platforms.interfaces.driver_platform_interface.DriverPlatformInterface` + +Configure VPX driver. + +`configure_light(number: str, subtype: str, platform_settings: dict) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure a VPX light. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure VPX switch. + +`get_hw_switch_states()` + +Return initial switch state. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse channel str to a list of channels. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Pulse on hit and hold, disable on disable_switch hit. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Pulse on hit and hold. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Pulse on hit, disable on disable_switch hit. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Pulse on hit and hold. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Pulse on hit and release. + +`vpx_changed_flashers()` + +Return changed lamps since last call. + +`vpx_changed_gi_strings()` + +Return changed lamps since last call. + +`vpx_changed_lamps()` + +Return changed lamps since last call. + +`vpx_changed_leds()` + +Return changed lamps since last call. + +`vpx_changed_solenoids()` + +Return changed solenoids since last call. + +`vpx_get_coilactive(number)` + +Return True if a MPF hw rule for the coil(number) exists. + +`vpx_get_hardwarerules()` + +Return hardware rules. + +`vpx_get_mech(number)` + +Not implemented. + +`vpx_get_switch(number)` + +Return switch value. + +`vpx_mech(number)` + +Not implemented. + +`vpx_pulsesw(number)` + +Pulse switch from VPX. + +`vpx_set_mech(number, value)` + +Not implemented. + +`vpx_set_switch(number, value)` + +Update switch from VPX. + +`vpx_start()` + +Start machine. + +`vpx_switch(number)` + +Return switch value. + diff --git a/docs/code/api_reference/devices/visual_pinball_evolution.md b/docs/code/api_reference/devices/visual_pinball_evolution.md new file mode 100644 index 0000000000..296b751984 --- /dev/null +++ b/docs/code/api_reference/devices/visual_pinball_evolution.md @@ -0,0 +1 @@ +# self.machine.hardware_platforms[‘visual_pinball_evolution’] diff --git a/docs/code/api_reference/hardware_platforms/drivers.md b/docs/code/api_reference/hardware_platforms/drivers.md new file mode 100644 index 0000000000..96b8ae7dc4 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/drivers.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘drivers’] + +`class mpf.platforms.driver_light_platform.DriverLightPlatform(machine)` + +Bases: mpf.core.platform.LightsPlatform + +Lights on drivers. + +## Accessing the drivers platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms dictionary`, so the drivers platform is available via `self.machine.hardware_platforms['drivers']`. + +## Methods & Attributes + +The drivers platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_light(number: str, subtype: str, platform_settings: dict) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure a light on a driver. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse number. + +`stop()` + +Stop all fades. + diff --git a/docs/code/api_reference/hardware_platforms/fadecandy.md b/docs/code/api_reference/hardware_platforms/fadecandy.md new file mode 100644 index 0000000000..2049521d35 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/fadecandy.md @@ -0,0 +1,17 @@ + +# self.machine.hardware_platforms[‘fadecandy’] + +`class mpf.platforms.fadecandy.FadecandyHardwarePlatform(machine: MachineController)` + +Bases: mpf.platforms.openpixel.OpenpixelHardwarePlatform + +Base class for the FadeCandy hardware platform. + +## Accessing the fadecandy platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the fadecandy platform is available via `self.machine.hardware_platforms['fadecandy']`. + +## Methods & Attributes + +The fadecandy platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + diff --git a/docs/code/api_reference/hardware_platforms/fast.md b/docs/code/api_reference/hardware_platforms/fast.md new file mode 100644 index 0000000000..e0d690d8bd --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/fast.md @@ -0,0 +1,224 @@ + +# self.machine.hardware_platforms[‘fast’] + +`class mpf.platforms.fast.fast.FastHardwarePlatform(machine)` + +Bases: mpf.core.platform.ServoPlatform, mpf.core.platform.LightsPlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform + +Platform class for the FAST hardware controller. + +## Accessing the fast platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the fast platform is available via `self.machine.hardware_platforms['fast']`. + +## Methods & Attributes + +The fast platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch, coil)` + +Clear a hardware rule. + +This is used if you want to remove the linkage between a switch and some driver activity. For example, if you wanted to disable your flippers (so that a player pushing the flipper buttons wouldn’t cause the flippers to flip), you’d call this method with your flipper button as the sw_num. + +Parameters: + +* **switch** – The switch whose rule you want to clear. +* **coil** – The coil whose rule you want to clear. + +`configure_dmd()` + +Configure a hardware DMD connected to a FAST controller. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict) → mpf.platforms.fast.fast_driver.FASTDriver` + +Configure a driver. + +Parameters: + +* **config** – Driver config. +* **number** – Number of this driver. +* **platform_settings** – Platform specific settings. + +Returns: Driver object + +`configure_light(number, subtype, platform_settings) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure light in platform. + +`configure_servo(number: str) → mpf.platforms.fast.fast_servo.FastServo` + +Configure a servo. + +Parameters: + +* **number** – Number of servo + +Returns: Servo object. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.fast.fast_switch.FASTSwitch` + +Configure the switch object for a FAST Pinball controller. + +FAST Controllers support two types of switches: local and network. Local switches are switches that are connected to the FAST controller board itself, and network switches are those connected to a FAST I/O board. + +MPF needs to know which type of switch is this is. You can specify the switch’s connection type in the config file via the connection: setting (either local or network). + +If a connection type is not specified, this method will use some intelligence to try to figure out which default should be used. + +If the DriverBoard type is fast, then it assumes the default is network. If it’s anything else (wpc, system11, bally, etc.) then it assumes the connection type is local. Connection types can be mixed and matched in the same machine. + +Parameters: + +* **number** – Number of this switch. +* **config** – Switch config. +* **platform_config** – Platform specific settings. + +Returns: Switch object. + +`static convert_number_from_config(number)` + +Convert a number from config format to hex. + +`classmethod get_coil_config_section()` + +Return coil config section. + +`get_hw_switch_states()` + +Return hardware states. + +`get_info_string()` + +Dump infos about boards. + +`classmethod get_switch_config_section()` + +Return switch config section. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse light channels from number string. + +`process_received_message(msg: str, remote_processor: str)` + +Send an incoming message from the FAST controller to the proper method for servicing. + +Parameters: + +* **msg** – messaged which was received +* **remote_processor** – Processor which sent the message. + +`receive_bootloader(msg, remote_processor)` + +Process bootloader message. + +`receive_local_closed(msg, remote_processor)` + +Process local switch closed. +Parameters: + +* **msg** – switch number +* **remote_processor** – Processor which sent the message. + +`receive_local_open(msg, remote_processor)` + +Process local switch open. + +Parameters: + +* **msg** – switch number +* **remote_processor** – Processor which sent the message. + +`receive_nw_closed(msg, remote_processor)` + +Process network switch closed. + +Parameters: + +* **msg** – switch number +* **remote_processor** – Processor which sent the message. + +`receive_nw_open(msg, remote_processor)` + +Process network switch open. + +Parameters: + +* **msg** – switch number +* **remote_processor** – Processor which sent the message. + +`receive_sa(msg, remote_processor)` + +Receive all switch states. + +Parameters: + +* **msg** – switch states as bytearray +* **remote_processor** – Processor which sent the message. + +`register_io_board(board)` + +Register an IO board. + +Parameters: + +* **board** – ‘mpf.platform.fast.fast_io_board.FastIoBoard’ to register + +`register_processor_connection(name: str, communicator)` + +Register processor. + +Once a communication link has been established with one of the processors on the FAST board, this method lets the communicator let MPF know which processor it’s talking to. + +This is a separate method since we don’t know which processor is on which serial port ahead of time. + +Parameters: + +* **communicator** – communicator object +* **name** – name of processor + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and enable and release and disable rule on driver. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and enable and relase rule on driver. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and release and disable rule on driver. + +`set_pulse_on_hit_and_release_rule(enable_switch, coil)` + +Set pulse on hit and release rule to driver. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit rule on driver. + +`start()` + +Start listening for commands and schedule watchdog. + +`stop()` + +Stop platform and close connections. + +`update_firmware() → str` + +Upgrade the firmware of the CPUs. + +`update_leds()` + +Update all the LEDs connected to a FAST controller. + +This is done once per game loop for efficiency (i.e. all LEDs are sent as a single update rather than lots of individual ones). + +Also, every LED is updated every loop, even if it doesn’t change. This is in case some interference causes a LED to change color. Since we update every loop, it will only be the wrong color for one tick. + diff --git a/docs/code/api_reference/hardware_platforms/i2c_servo_controller.md b/docs/code/api_reference/hardware_platforms/i2c_servo_controller.md new file mode 100644 index 0000000000..90753b39f3 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/i2c_servo_controller.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘i2c_servo_controller’] + +`class mpf.platforms.i2c_servo_controller.I2CServoControllerHardwarePlatform(machine)` + +Bases: mpf.core.platform.ServoPlatform + +Supports the PCA9685/PCA9635 chip via I2C. + +## Accessing the i2c_servo_controller platform via code + +Hardware platforms are stored in the self.machine.hardware_platforms dictionary, so the i2c_servo_controller platform is available via `self.machine.hardware_platforms['i2c_servo_controller']`. + +## Methods & Attributes + +The i2c_servo_controller platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_servo(number: str)` + +Configure servo. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/light_segment_displays.md b/docs/code/api_reference/hardware_platforms/light_segment_displays.md new file mode 100644 index 0000000000..47bedb484c --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/light_segment_displays.md @@ -0,0 +1,21 @@ + +# self.machine.hardware_platforms[‘light_segment_displays’] + +`class mpf.platforms.light_segment_displays.LightSegmentDisplaysPlatform(machine)` + +Bases: mpf.core.platform.SegmentDisplayPlatform + +Platform which drives segment displays on lights of another platform. + +## Accessing the light_segment_displays platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the light_segment_displays platform is available via `self.machine.hardware_platforms['light_segment_displays']`. + +## Methods & Attributes + +The light_segment_displays platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.light_segment_displays.LightSegmentDisplay` + +Configure light segment display. + diff --git a/docs/code/api_reference/hardware_platforms/lisy.md b/docs/code/api_reference/hardware_platforms/lisy.md new file mode 100644 index 0000000000..5f9ccc21b3 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/lisy.md @@ -0,0 +1,101 @@ + +# self.machine.hardware_platforms[‘lisy’] + +`class mpf.platforms.lisy.lisy.LisyHardwarePlatform(machine)` + +Bases: mpf.core.platform.SwitchPlatform, mpf.core.platform.LightsPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.SegmentDisplaySoftwareFlashPlatform, mpf.core.platform.HardwareSoundPlatform, mpf.core.logging.LogMixin + +LISY platform. + +## Accessing the lisy platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the lisy platform is available via `self.machine.hardware_platforms['lisy']`. + +## Methods & Attributes + +The lisy platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Clear hw rule for driver. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict) → mpf.platforms.interfaces.driver_platform_interface.DriverPlatformInterface` + +Configure a driver. + +`configure_hardware_sound_system() → mpf.platforms.interfaces.hardware_sound_platform_interface.HardwareSoundPlatformInterface` + +Configure hardware sound. + +`configure_light(number: str, subtype: str, platform_settings: dict) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure light on LISY. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.interfaces.segment_display_platform_interface.SegmentDisplaySoftwareFlashPlatformInterface` + +Configure a segment display. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure a switch. + +`get_hw_switch_states()` + +Return current switch states. + +`get_info_string()` + +Dump infos about LISY platform. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Return a single light. + +`send_byte(cmd: int, byte: bytes = None)` + +Send a command with optional payload. + +`send_byte_and_read_response(cmd: int, byte: bytes = None, read_bytes=0)` + +Send byte and read response. + +`send_string(cmd: int, string: str)` + +Send a command with null terminated string. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and enable and release and disable rule on driver. + +Pulses a driver when a switch is hit. Then enables the driver (may be with pwm). When the switch is released the pulse is canceled and the driver becomes disabled. When the eos_switch is hit the pulse is canceled and the driver becomes enabled (likely with PWM). Typically used on the coil for single-wound coil flippers with eos switch. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and enable and release rule on driver. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and enable and release and disable rule on driver. + +Pulses a driver when a switch is hit. When the switch is released the pulse is canceled and the driver gets disabled. When the eos_switch is hit the pulse is canceled and the driver becomes disabled. Typically used on the main coil for dual-wound coil flippers with eos switch. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and release rule to driver. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit rule on driver. + +`start()` + +Start reading switch changes. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/mma8451.md b/docs/code/api_reference/hardware_platforms/mma8451.md new file mode 100644 index 0000000000..df4cc3e18f --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/mma8451.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘mma8451’] + +`class mpf.platforms.mma8451.MMA8451Platform(machine)` + +Bases: mpf.core.platform.AccelerometerPlatform + +MMA8451 accelerometer platform. + +## Accessing the mma8451 platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the mma8451 platform is available via `self.machine.hardware_platforms['mma8451']`. + +## Methods & Attributes + +The mma8451 platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_accelerometer(number, config, callback) → mpf.platforms.mma8451.MMA8451Device` + +Configure MMA8451 accelerometer. + +`initialize()` + +Initialise MMA8451 platform. + +`stop()` + +Stop accelerometer poll tasks. + diff --git a/docs/code/api_reference/hardware_platforms/mypinballs.md b/docs/code/api_reference/hardware_platforms/mypinballs.md new file mode 100644 index 0000000000..651207810d --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/mypinballs.md @@ -0,0 +1,33 @@ + +# self.machine.hardware_platforms[‘mypinballs’] + +`class mpf.platforms.mypinballs.mypinballs.MyPinballsHardwarePlatform(machine)` + +Bases: mpf.core.platform.SegmentDisplayPlatform + +Hardware platform for MyPinballs 7-segment controller. + +## Accessing the mypinballs platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the mypinballs platform is available via `self.machine.hardware_platforms['mypinballs']`. + +## Methods & Attributes + +The mypinballs platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.interfaces.segment_display_platform_interface.SegmentDisplayPlatformInterface` + +Configure display. + +`initialize()` + +Initialise hardware. + +`send_cmd(cmd: bytes)` + +Send a byte command. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/openpixel.md b/docs/code/api_reference/hardware_platforms/openpixel.md new file mode 100644 index 0000000000..eb7c988b1b --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/openpixel.md @@ -0,0 +1,37 @@ + +# self.machine.hardware_platforms[‘openpixel’] + +`class mpf.platforms.openpixel.OpenpixelHardwarePlatform(machine: MachineController)` + +Bases: mpf.core.platform.LightsPlatform + +Base class for the open pixel hardware platform. + +Parameters: + +* **machine** – The main MachineController object. + +## Accessing the openpixel platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the openpixel platform is available via `self.machine.hardware_platforms['openpixel']`. + +## Methods & Attributes + +The openpixel platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_light(number, subtype, platform_settings) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure an LED. + +`initialize()` + +Initialise openpixel platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse number to three channels. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/opp.md b/docs/code/api_reference/hardware_platforms/opp.md new file mode 100644 index 0000000000..820e7eccc9 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/opp.md @@ -0,0 +1,222 @@ +# self.machine.hardware_platforms[‘opp’] + +`class mpf.platforms.opp.opp.OppHardwarePlatform(machine)` + +Bases: mpf.core.platform.LightsPlatform, mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform + +Platform class for the OPP hardware. + +Parameters: + +* **machine** – The main MachineController instance. + +## Accessing the opp platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the opp platform is available via `self.machine.hardware_platforms['opp']`. + +## Methods & Attributes + +The opp platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Clear a hardware rule. + +This is used if you want to remove the linkage between a switch and some driver activity. For example, if you wanted to disable your flippers (so that a player pushing the flipper buttons wouldn’t cause the flippers to flip), you’d call this method with your flipper button as the sw_num. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure a driver. + +Parameters: + +* **config** – Config dict. +* **number** – Number of this driver. +* **platform_settings** – Platform specific settings. + +`configure_light(number, subtype, platform_settings)` + +Configure a led or matrix light. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure a switch. + +Parameters: + +* **number** – Number of this switch. +* **config** – Config dict. +* **platform_config** – Platform specific settings. + +`static eom_resp(chain_serial, msg)` + +Process an EOM. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`classmethod get_coil_config_section()` + +Return coil config section. + +`get_gen2_cfg_resp(chain_serial, msg)` + +Process cfg response. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`get_hw_switch_states()` + +Get initial hardware switch states. + +This changes switches from active low to active high + +`get_info_string()` + +Dump infos about boards. + +`initialize()` + +Initialise connections to OPP hardware. + +`inv_resp(chain_serial, msg)` + +Parse inventory response. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse number and subtype to channel. + +`process_received_message(chain_serial, msg)` + +Send an incoming message from the OPP hardware to the proper method for servicing. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`read_gen2_inp_resp(chain_serial, msg)` + +Read switch changes. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`read_gen2_inp_resp_initial(chain_serial, msg)` + +Read initial switch states. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`read_matrix_inp_resp(chain_serial, msg)` + +Read matrix switch changes. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`read_matrix_inp_resp_initial(chain_serial, msg)` + +Read initial matrix switch states. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. + +`register_processor_connection(serial_number, communicator)` + +Register the processors to the platform. + +Parameters: + +* **serial_number** – Serial number of chain. +* **communicator** – Instance of OPPSerialCommunicator + +`send_to_processor(chain_serial, msg)` + +Send message to processor with specific serial number. + +Parameters: + +* **chain_serial** – Serial of the processor. +* **msg** – Message to send. + +`set_delayed_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, delay_ms: int)` + +Set pulse on hit and release rule to driver. + +When a switch is hit and a certain delay passed it pulses a driver. When the switch is released the pulse continues. Typically used for kickbacks. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and enable and release and disable rule on driver. + +Pulses a driver when a switch is hit. Then enables the driver (may be with pwm). When the switch is released the pulse is canceled and the driver becomes disabled. When the eos_switch is hit the pulse is canceled and the driver becomes enabled (likely with PWM). Typically used on the coil for single-wound coil flippers with eos switch. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and enable and relase rule on driver. + +Pulses a driver when a switch is hit. Then enables the driver (may be with pwm). When the switch is released the pulse is canceled and the driver gets disabled. Typically used for single coil flippers. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and release and disable rule on driver. + +Pulses a driver when a switch is hit. Then enables the driver (may be with pwm). When the switch is released the pulse is canceled and the driver gets disabled. When the second disable_switch is hit the pulse is canceled and the driver gets disabled. Typically used on the main coil for dual coil flippers with eos switch. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and release rule to driver. + +Pulses a driver when a switch is hit. When the switch is released the pulse is canceled. Typically used on the main coil for dual coil flippers without eos switch. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit rule on driver. + +Pulses a driver when a switch is hit. When the switch is released the pulse continues. Typically used for autofire coils such as pop bumpers. + +`start()` + +Start polling and listening for commands. + +`stop()` + +Stop hardware and close connections. + +`update_incand()` + +Update all the incandescents connected to OPP hardware. + +This is done once per game loop if changes have been made. + +It is currently assumed that the UART oversampling will guarantee proper communication with the boards. If this does not end up being the case, this will be changed to update all the incandescents each loop. + +`vers_resp(chain_serial, msg)` + +Process version response. + +Parameters: + +* **chain_serial** – Serial of the chain which received the message. +* **msg** – Message to parse. diff --git a/docs/code/api_reference/hardware_platforms/osc.md b/docs/code/api_reference/hardware_platforms/osc.md new file mode 100644 index 0000000000..545a8cd8d9 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/osc.md @@ -0,0 +1,41 @@ + +# self.machine.hardware_platforms[‘osc’] + +`class mpf.platforms.osc.OscPlatform(machine)` + +Bases: mpf.core.platform.LightsPlatform, mpf.core.platform.SwitchPlatform + +A platform to control lights via OSC. + +## Accessing the osc platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms dictionary`, so the osc platform is available via `self.machine.hardware_platforms['osc']`. + +## Methods & Attributes + +The osc platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_light(number: str, subtype: str, platform_settings: dict) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure an OSC light. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Config an OSC switch. + +`get_hw_switch_states() → Dict[str, bool]` + +Return all switches as false. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse light number to three RGB channels. + +`stop()` + +Stop server. + diff --git a/docs/code/api_reference/hardware_platforms/p3_roc.md b/docs/code/api_reference/hardware_platforms/p3_roc.md new file mode 100644 index 0000000000..ece0b12fbf --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/p3_roc.md @@ -0,0 +1,89 @@ + +# self.machine.hardware_platforms[‘p3_roc’] + +`class mpf.platforms.p3_roc.P3RocHardwarePlatform(machine)` + +Bases: mpf.platforms.p_roc_common.PROCBasePlatform, mpf.core.platform.I2cPlatform, mpf.core.platform.AccelerometerPlatform + +Platform class for the P3-ROC hardware controller. + +Parameters: + +* **machine** – The MachineController instance. + +## Accessing the p3_roc platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the p3_roc platform is available via `self.machine.hardware_platforms['p3_roc']`. + +## Methods & Attributes + +The p3_roc platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_accelerometer(number, config, callback)` + +Configure the accelerometer on the P3-ROC. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Create a P3-ROC driver. + +Typically drivers are coils or flashers, but for the P3-ROC this is also used for matrix-based lights. + +Parameters: + +* **config** – Dictionary of settings for the driver. +* **number** – Number of this driver. +* **platform_settings** – Platform specific settings + +Returns a reference to the PROCDriver object which is the actual object you can use to pulse(), patter(), enable(), etc. + +`configure_i2c(number: str)` + +Configure I2C device on P3-Roc. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure a P3-ROC switch. + +Parameters: + +* **number** – Number of this switch +* **config** – Dictionary of settings for the switch. +* **platform_config** – Platform specific settings. + +Returns: A configured switch object. + +`connect()` + +Connect to the P3-Roc. + +`get_hw_switch_states() → Dict[str, bool]` + +Read in and set the initial switch state. + +The P-ROC uses the following values for hw switch states: 1 - closed (debounced) 2 - open (debounced) 3 - closed (not debounced) 4 - open (not debounced) + +`get_info_string()` + +Dump infos about boards. + +`process_events(events)` + +Process events from the P3-Roc. + +`classmethod scale_accelerometer_to_g(raw_value)` + +Convert internal representation to g. + +`set_gpio(index, state)` + +Set GPIO state. + +`start()` + +Start GPIO poller. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/p_roc.md b/docs/code/api_reference/hardware_platforms/p_roc.md new file mode 100644 index 0000000000..d249d423cd --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/p_roc.md @@ -0,0 +1,73 @@ + +# self.machine.hardware_platforms[‘p_roc’] + +`class mpf.platforms.p_roc.PRocHardwarePlatform(machine)` + +Bases: mpf.platforms.p_roc_common.PROCBasePlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.SegmentDisplayPlatform + +Platform class for the P-ROC hardware controller. + +Parameters: + +* **machine** – The MachineController instance. + +## Accessing the p_roc platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the p_roc platform is available via `self.machine.hardware_platforms['p_roc']`. + +## Methods & Attributes + +The p_roc platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_dmd()` + +Configure a hardware DMD connected to a classic P-ROC. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Create a P-ROC driver. + +Typically drivers are coils or flashers, but for the P-ROC this is also used for matrix-based lights. + +Parameters: + +* **config** – Dictionary of settings for the driver. +* **number** – Number of this driver +* **platform_settings** – Platform specific setting for this driver. + +Returns a reference to the PROCDriver object which is the actual object you can use to pulse(), patter(), enable(), etc. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.interfaces.segment_display_platform_interface.SegmentDisplayPlatformInterface` + +Configure display. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure a P-ROC switch. + +Parameters: + +* **number** – String number of the switch to configure. +* **config** – SwitchConfig settings. +* **platform_config** – Platform specific settings. + +Returns: A configured switch object. + +`connect()` + +Connect to the P-Roc. + +`get_hw_switch_states() → Dict[str, bool]` + +Read in and set the initial switch state. + +The P-ROC uses the following values for hw switch states: 1 - closed (debounced) 2 - open (debounced) 3 - closed (not debounced) 4 - open (not debounced) + +`get_info_string()` + +Dump infos about boards. + +`process_events(events)` + +Process events from the P-Roc. + diff --git a/docs/code/api_reference/hardware_platforms/pin2dmd.md b/docs/code/api_reference/hardware_platforms/pin2dmd.md new file mode 100644 index 0000000000..204882fe5e --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/pin2dmd.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘pin2dmd’] + +`class mpf.platforms.pin2dmd.Pin2DmdHardwarePlatform(machine)` + +Bases: mpf.core.platform.RgbDmdPlatform + +PIN2DMD RGB DMD hardware. + +## Accessing the pin2dmd platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the pin2dmd platform is available via `self.machine.hardware_platforms['pin2dmd']`. + +## Methods & Attributes + +The pin2dmd platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_rgb_dmd(name: str)` + +Configure rgb dmd. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/pololu_maestro.md b/docs/code/api_reference/hardware_platforms/pololu_maestro.md new file mode 100644 index 0000000000..d2bab5772e --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/pololu_maestro.md @@ -0,0 +1,35 @@ + +# self.machine.hardware_platforms[‘pololu_maestro’] + +`class mpf.platforms.pololu_maestro.PololuMaestroHardwarePlatform(machine)` + +Bases: mpf.core.platform.ServoPlatform + +Supports the Pololu Maestro servo controllers via PySerial. + +Works with Micro Maestro 6, and Mini Maestro 12, 18, and 24. + +## Accessing the pololu_maestro platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the pololu_maestro platform is available via `self.machine.hardware_platforms['pololu_maestro'].` + +## Methods & Attributes + +`The pololu_maestro platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_servo(number: str)` + +Configure a servo device in platform. + +Parameters: + +* **number** – Number of the servo. + +`initialize()` + +Initialise platform. + +`stop()` + +Close serial. + diff --git a/docs/code/api_reference/hardware_platforms/pololu_tic.md b/docs/code/api_reference/hardware_platforms/pololu_tic.md new file mode 100644 index 0000000000..bc7242db12 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/pololu_tic.md @@ -0,0 +1,34 @@ + +# self.machine.hardware_platforms[‘pololu_tic’] + +`class mpf.platforms.pololu.pololu_tic.PololuTICHardwarePlatform(machine)` + +Bases: mpf.core.platform.StepperPlatform + +Supports the Pololu TIC stepper drivers via ticcmd command line. + +## Accessing the pololu_tic platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the pololu_tic platform is available via `self.machine.hardware_platforms['pololu_tic']`. + +## Methods & Attributes + +The pololu_tic platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_stepper(number: str, config: dict) → mpf.platforms.pololu.pololu_tic.PololuTICStepper` + +Configure a smart stepper device in platform. + +Parameters: + +* **number** – Number of this stepper. +* **config (dict)** – Configuration of device + +`classmethod get_stepper_config_section()` + +Return config validator name. + +`stop()` + +De-energize the stepper and stop sending the command timeout refresh. + diff --git a/docs/code/api_reference/hardware_platforms/rpi.md b/docs/code/api_reference/hardware_platforms/rpi.md new file mode 100644 index 0000000000..af5b49ede4 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/rpi.md @@ -0,0 +1,75 @@ + +# self.machine.hardware_platforms[‘rpi’] + +`class mpf.platforms.rpi.rpi.RaspberryPiHardwarePlatform(machine)` + +Bases: mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.ServoPlatform, mpf.core.platform.I2cPlatform + +Control the hardware of a Raspberry Pi. + +Works locally and remotely via network. + +## Accessing the rpi platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the rpi platform is available via `self.machine.hardware_platforms['rpi']`. + +## Methods & Attributes + +The rpi platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict) → mpf.platforms.interfaces.driver_platform_interface.DriverPlatformInterface` + +Configure an output on the Raspberry Pi. + +`configure_i2c(number: str)` + +Configure I2c device. + +`configure_servo(number: str) → mpf.platforms.interfaces.servo_platform_interface.ServoPlatformInterface` + +Configure a servo. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure a switch with pull up. + +`get_hw_switch_states()` + +Return current switch states. + +`initialize()` + +Initialise platform. + +`send_command(cmd)` + +Add a command to the command queue. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Raise exception. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Raise exception. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Raise exception. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/rpi_dmd.md b/docs/code/api_reference/hardware_platforms/rpi_dmd.md new file mode 100644 index 0000000000..872fdd19c7 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/rpi_dmd.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘rpi_dmd’] + +`class mpf.platforms.rpi_dmd.RpiDmdPlatform(machine)` + +Bases: mpf.core.platform.RgbDmdPlatform + +Raspberry Pi GPIO RGB DMD. + +## Accessing the rpi_dmd platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the rpi_dmd platform is available via `self.machine.hardware_platforms['rpi_dmd']`. + +## Methods & Attributes + +The rpi_dmd platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_rgb_dmd(name: str)` + +Configure rgb dmd. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/smart_virtual.md b/docs/code/api_reference/hardware_platforms/smart_virtual.md new file mode 100644 index 0000000000..7fa2a123cc --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/smart_virtual.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘smart_virtual’] + +`class mpf.platforms.smart_virtual.SmartVirtualHardwarePlatform(machine)` + +Bases: mpf.platforms.virtual.VirtualHardwarePlatform + +Base class for the smart_virtual hardware platform. + +## Accessing the smart_virtual platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the smart_virtual platform is available via `self.machine.hardware_platforms['smart_virtual']`. + +## Methods & Attributes + +The smart_virtual platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`add_ball_to_device(device: mpf.devices.ball_device.ball_device.BallDevice)` + +Add ball to device. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure driver. + +`start()` + +Initialise platform when all devices are ready. + diff --git a/docs/code/api_reference/hardware_platforms/smartmatrix.md b/docs/code/api_reference/hardware_platforms/smartmatrix.md new file mode 100644 index 0000000000..3c0f2129c7 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/smartmatrix.md @@ -0,0 +1,29 @@ + +# self.machine.hardware_platforms[‘smartmatrix’] + +`class mpf.platforms.smartmatrix.SmartMatrixHardwarePlatform(machine)` + +Bases: mpf.core.platform.RgbDmdPlatform + +SmartMatrix RGB DMD. + +## Accessing the smartmatrix platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the smartmatrix platform is available via `self.machine.hardware_platforms['smartmatrix']`. + +## Methods & Attributes + +The smartmatrix platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_rgb_dmd(name: str)` + +Configure rgb dmd. + +`initialize()` + +Initialise platform. + +`stop()` + +Stop platform. + diff --git a/docs/code/api_reference/hardware_platforms/smbus2.md b/docs/code/api_reference/hardware_platforms/smbus2.md new file mode 100644 index 0000000000..c40bbeb7a5 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/smbus2.md @@ -0,0 +1,25 @@ + +# self.machine.hardware_platforms[‘smbus2’] + +`class mpf.platforms.smbus2.Smbus2(machine)` + +Bases: mpf.core.platform.I2cPlatform + +I2C platform which uses the smbus interface on linux via the smbus2 python extension. + +## Accessing the smbus2 platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the smbus2 platform is available via `self.machine.hardware_platforms['smbus2']`. + +## Methods & Attributes + +The smbus2 platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_i2c(number: str) → mpf.platforms.smbus2.Smbus2I2cDevice` + +Configure device on smbus2. + +`initialize()` + +Check if smbus2 extension has been imported. + diff --git a/docs/code/api_reference/hardware_platforms/snux.md b/docs/code/api_reference/hardware_platforms/snux.md new file mode 100644 index 0000000000..90a5af9792 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/snux.md @@ -0,0 +1,17 @@ + +# self.machine.hardware_platforms[‘snux’] + +`class mpf.platforms.snux.SnuxHardwarePlatform(machine: mpf.core.machine.MachineController)` + +Bases: mpf.platforms.system11.System11OverlayPlatform + +Overlay platform for the snux hardware board. + +## Accessing the snux platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the snux platform is available via `self.machine.hardware_platforms['snux']`. + +## Methods & Attributes + +The snux platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + diff --git a/docs/code/api_reference/hardware_platforms/spi_bit_bang.md b/docs/code/api_reference/hardware_platforms/spi_bit_bang.md new file mode 100644 index 0000000000..13a05b7f09 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/spi_bit_bang.md @@ -0,0 +1,35 @@ + +# self.machine.hardware_platforms[‘spi_bit_bang’] + +`class mpf.platforms.spi_bit_bang.SpiBitBangPlatform(machine)` + +Bases: mpf.core.platform.SwitchPlatform + +Platform which reads switch via SPI using bit banging. + +## Accessing the spi_bit_bang platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the spi_bit_bang platform is available via `self.machine.hardware_platforms['spi_bit_bang']`. + +## Methods & Attributes + +The spi_bit_bang platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure switch. + +`get_hw_switch_states()` + +Read initial hardware state. + +This will always be false for all inputs on those switches. + +`initialize()` + +Register handler for late init. + +`read_spi(bits)` + +Read from SPI. + diff --git a/docs/code/api_reference/hardware_platforms/spike.md b/docs/code/api_reference/hardware_platforms/spike.md new file mode 100644 index 0000000000..9d49af64d4 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/spike.md @@ -0,0 +1,119 @@ + +# self.machine.hardware_platforms[‘spike’] + +class mpf.platforms.spike.spike.SpikePlatform(machine) + +Bases: mpf.core.platform.SwitchPlatform, mpf.core.platform.LightsPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.StepperPlatform + +Stern Spike Platform. + +## Accessing the spike platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the spike platform is available via `self.machine.hardware_platforms['spike']`. + +## Methods & Attributes + +The spike platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch, coil)` + +Disable hardware rule for this coil. + +`configure_dmd()` + +Configure a DMD. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure a driver on Stern Spike. + +`configure_light(number, subtype, platform_settings) → Union[mpf.platforms.spike.spike.SpikeLight, mpf.platforms.spike.spike.SpikeBacklight]` + +Configure a light on Stern Spike. + +`configure_stepper(number: str, config: dict) → mpf.platforms.interfaces.stepper_platform_interface.StepperPlatformInterface` + +Configure a stepper in Spike. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure switch on Stern Spike. + +`get_hw_switch_states()` + +Return current switch states. + +`classmethod get_stepper_config_section()` + +Return config validator name. + +`classmethod get_switch_config_section()` + +Return switch config section. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Return a single light. + +`send_cmd_and_wait_for_response(node, cmd, data, response_len) → Optional[bytearray]` + +Send cmd and wait for response. + +`send_cmd_async(node, cmd, data)` + +Send cmd which does not require a response. + +`send_cmd_raw(data, wait_ms=0)` + +Send raw command. + +`send_cmd_raw_async(data, wait_ms=0)` + +Send raw cmd which does not require a response. + +`send_cmd_sync(node, cmd, data)` + +Send cmd which does not require a response. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and release rule to driver. + +Used for high-power coil on single-wound flippers. Example from GoT: Node: 8 Command CoilSetReflex (0x41) Params: 0x00 0xff 0x33 0x00 0x1e 0x28 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x42 0x00 0x00 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x05 0x06 0x00 Len: 36 + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and enable and release rule on driver. + +Used for single coil flippers. Examples from WWE: Dual-wound flipper hold coil: Type: 8 Cmd: 65 Node: 8 Msg: 0x02 0xff 0x46 0x01 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3a 0x00 0x42 0x40 0x00 0x00 0x01 0x00 Len: 25 + +Ring Slings (different flags): Type: 8 Cmd: 65 Node: 10 Msg: 0x00 0xff 0x19 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x4a 0x40 0x00 0x00 0x06 0x05 Len: 25 + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set pulse on hit and release rule to driver. + +Used for high-power coil on dual-wound flippers. Example from WWE: Type: 8 Cmd: 65 Node: 8 Msg: 0x00 0xff 0x33 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x42 0x40 0x00 0x02 0x06 0x00 Len: 25 + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit and release rule to driver. + +I believe that param2 == 1 means that it will cancel the pulse when the switch is released. + +Used for high-power coils on dual-wound flippers. Example from WWE: Type: 8 Cmd: 65 Node: 8 Msg: 0x03 0xff 0x46 0x01 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x43 0x40 0x00 0x00 0x01 0x00 Len: 25 + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Set pulse on hit rule on driver. + +This is mostly used for popbumpers. Example from WWE: Type: 8 Cmd: 65 Node: 9 Msg: 0x00 0xa6 0x28 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x14 0x00 0x00 0x00 0x38 0x00 0x40 0x00 0x00 0x00 0x00 0x00 Len: 25 + +`stop()` + +Stop hardware and close connections. + diff --git a/docs/code/api_reference/hardware_platforms/step_stick.md b/docs/code/api_reference/hardware_platforms/step_stick.md new file mode 100644 index 0000000000..c96084a547 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/step_stick.md @@ -0,0 +1,25 @@ + +# self.machine.hardware_platforms[‘step_stick’] + +`class mpf.platforms.step_stick.StepStickDigitalOutputPlatform(machine)` + +Bases: mpf.core.platform.StepperPlatform + +Drive a stepper using a StepStick controller on a digital output. + +## Accessing the step_stick platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the step_stick platform is available via `self.machine.hardware_platforms['step_stick']`. + +## Methods & Attributes + +The step_stick platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_stepper(number: str, config: dict) → mpf.platforms.interfaces.stepper_platform_interface.StepperPlatformInterface` + +Configure a stepper driven by StepStick on a digital output. + +`classmethod get_stepper_config_section()` + +Return config section. + diff --git a/docs/code/api_reference/hardware_platforms/system11.md b/docs/code/api_reference/hardware_platforms/system11.md new file mode 100644 index 0000000000..06af5b97e9 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/system11.md @@ -0,0 +1,116 @@ + +# self.machine.hardware_platforms[‘system11’] + +`class mpf.platforms.system11.System11OverlayPlatform(machine: mpf.core.machine.MachineController)` + +Bases: mpf.core.platform.DriverPlatform, mpf.core.platform.SwitchPlatform + +Overlay platform to drive system11 machines using a WPC controller. + +## Accessing the system11 platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the system11 platform is available via `self.machine.hardware_platforms['system11']`. + +## Methods & Attributes + +The system11 platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`a_side_active` + +Return if A side cannot be switches off right away. + +`a_side_busy` + +Return if A side cannot be switches off right away. + +`c_side_active` + +Return if C side cannot be switches off right away. + +`c_side_busy` + +Return if C side cannot be switches off right away. + +`clear_hw_rule(switch, coil)` + +Clear a rule for a driver on the system11 overlay. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure a driver on the system11 overlay. + +Parameters: + +* **config** – Driver config dict +* **number** – Number of the driver. +* **platform_settings** – Platform specific config. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure switch on system11 overlay. + +`driver_action(driver, pulse_settings: Optional[mpf.platforms.interfaces.driver_platform_interface.PulseSettings], hold_settings: Optional[mpf.platforms.interfaces.driver_platform_interface.HoldSettings], side: str)` + +Add a driver action for a switched driver to the queue (for either the A-side or C-side queue). + +Parameters: + +* **driver** – A reference to the original platform class Driver instance. +* **pulse_settings** – Settings for the pulse or None +* **hold_settings** – Settings for hold or None +* **side** – Whatever the driver is on A or C side. + +This action will be serviced immediately if it can, or ASAP otherwise. + +`get_hw_switch_states()` + +Get initial hardware state. + +`initialize()` + +Automatically called by the Platform class after all the core modules are loaded. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch, coil)` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_and_release_rule(enable_switch, coil)` + +Configure a rule for a driver on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`set_pulse_on_hit_rule(enable_switch, coil)` + +Configure a rule on the system11 overlay. + +Will pass the call onto the parent platform if the driver is not on A/C relay. + +`stop()` + +Stop the overlay. Nothing to do here because stop is also called on parent platform. + +`tick()` + +System11 main loop. + +Called based on the timer_tick event. + +`validate_coil_section(driver, config)` + +Validate coil config for platform. + diff --git a/docs/code/api_reference/hardware_platforms/trinamics_steprocker.md b/docs/code/api_reference/hardware_platforms/trinamics_steprocker.md new file mode 100644 index 0000000000..7f02fca508 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/trinamics_steprocker.md @@ -0,0 +1,39 @@ + +# self.machine.hardware_platforms[‘trinamics_steprocker’] + +`class mpf.platforms.trinamics_steprocker.TrinamicsStepRocker(machine)` + +Bases: mpf.core.platform.StepperPlatform + +Supports the Trinamics Step Rocker via PySerial. + +Works with Trinamics Step Rocker. TBD other ‘TMCL’ based steppers eval boards + +## Accessing the trinamics_steprocker platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the trinamics_steprocker platform is available via `self.machine.hardware_platforms['trinamics_steprocker']`. + +## Methods & Attributes + +The trinamics_steprocker platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`configure_stepper(number: str, config: dict) → mpf.platforms.trinamics_steprocker.TrinamicsTMCLStepper` + +Configure a smart stepper device in platform. + +Parameters: + +* **number** – Number of the stepper. +* **config (dict)** – Configuration of device + +`classmethod get_stepper_config_section()` + +Return config validator name. + +`initialize()` + +Initialise trinamics steprocker platform. + +`stop()` + +Close serial. diff --git a/docs/code/api_reference/hardware_platforms/virtual.md b/docs/code/api_reference/hardware_platforms/virtual.md new file mode 100644 index 0000000000..e4c4551083 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/virtual.md @@ -0,0 +1,113 @@ + +# self.machine.hardware_platforms[‘virtual’] + +`class mpf.platforms.virtual.VirtualHardwarePlatform(machine)` + +Bases: mpf.core.platform.AccelerometerPlatform, mpf.core.platform.I2cPlatform, mpf.core.platform.ServoPlatform, mpf.core.platform.LightsPlatform, mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform, mpf.core.platform.DmdPlatform, mpf.core.platform.RgbDmdPlatform, mpf.core.platform.SegmentDisplayPlatform, mpf.core.platform.StepperPlatform, mpf.core.platform.HardwareSoundPlatform + +Base class for the virtual hardware platform. + +## Accessing the virtual platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the virtual platform is available via `self.machine.hardware_platforms['virtual']`. + +## Methods & Attributes + +The virtual platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch, coil)` + +Clear hw rule. + +`configure_accelerometer(number, config, callback)` + +Configure accelerometer. + +`configure_dmd()` + +Configure DMD. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict)` + +Configure driver. + +`configure_hardware_sound_system() → mpf.platforms.interfaces.hardware_sound_platform_interface.HardwareSoundPlatformInterface` + +Configure virtual hardware sound system. + +`configure_i2c(number: str) → mpf.platforms.interfaces.i2c_platform_interface.I2cPlatformInterface` + +Configure virtual i2c device. + +`configure_light(number, subtype, platform_settings)` + +Configure light channel. + +`configure_rgb_dmd(name: str)` + +Configure DMD. + +`configure_segment_display(number: str, platform_settings) → mpf.platforms.interfaces.segment_display_platform_interface.SegmentDisplayPlatformInterface` + +Configure segment display. + +`configure_servo(number: str)` + +Configure a servo device in platform. + +`configure_stepper(number: str, config: dict)` + +Configure a smart stepper / axis device in platform. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict)` + +Configure switch. + +`get_hw_switch_states()` + +Return hw switch states. + +`initialize() → None` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse channel str to a list of channels. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set rule. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch, coil)` + +Set rule. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Set rule. + +`set_pulse_on_hit_and_release_rule(enable_switch, coil)` + +Set rule. + +`set_pulse_on_hit_rule(enable_switch, coil)` + +Set rule. + +`stop()` + +Stop platform. + +`validate_coil_section(driver, config)` + +Validate coil sections. + +`validate_stepper_section(stepper, config)` + +Validate stepper sections. + +`validate_switch_section(switch, config)` + +Validate switch sections. + diff --git a/docs/code/api_reference/hardware_platforms/virtual_pinball.md b/docs/code/api_reference/hardware_platforms/virtual_pinball.md new file mode 100644 index 0000000000..566dfe92fe --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/virtual_pinball.md @@ -0,0 +1,125 @@ + +# self.machine.hardware_platforms[‘virtual_pinball’] + +`class mpf.platforms.virtual_pinball.virtual_pinball.VirtualPinballPlatform(machine)` + +Bases: mpf.core.platform.LightsPlatform, mpf.core.platform.SwitchPlatform, mpf.core.platform.DriverPlatform + +VPX platform. + +## Accessing the virtual_pinball platform via code + +Hardware platforms are stored in the `self.machine.hardware_platforms` dictionary, so the virtual_pinball platform is available via `self.machine.hardware_platforms['virtual_pinball']`. + +## Methods & Attributes + +The virtual_pinball platform has the following methods & attributes available. Note that methods & attributes inherited from base classes are not included here. + +`clear_hw_rule(switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Clear hw rule. + +`configure_driver(config: mpf.core.platform.DriverConfig, number: str, platform_settings: dict) → mpf.platforms.interfaces.driver_platform_interface.DriverPlatformInterface` + +Configure VPX driver. + +`configure_light(number: str, subtype: str, platform_settings: dict) → mpf.platforms.interfaces.light_platform_interface.LightPlatformInterface` + +Configure a VPX light. + +`configure_switch(number: str, config: mpf.core.platform.SwitchConfig, platform_config: dict) → mpf.platforms.interfaces.switch_platform_interface.SwitchPlatformInterface` + +Configure VPX switch. + +`get_hw_switch_states()` + +Return initial switch state. + +`initialize()` + +Initialise platform. + +`parse_light_number_to_channels(number: str, subtype: str)` + +Parse channel str to a list of channels. + +`set_pulse_on_hit_and_enable_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Pulse on hit and hold, disable on disable_switch hit. + +`set_pulse_on_hit_and_enable_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Pulse on hit and hold. + +`set_pulse_on_hit_and_release_and_disable_rule(enable_switch: mpf.core.platform.SwitchSettings, eos_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings, repulse_settings: Optional[mpf.core.platform.RepulseSettings])` + +Pulse on hit, disable on disable_switch hit. + +`set_pulse_on_hit_and_release_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Pulse on hit and hold. + +`set_pulse_on_hit_rule(enable_switch: mpf.core.platform.SwitchSettings, coil: mpf.core.platform.DriverSettings)` + +Pulse on hit and release. + +`vpx_changed_flashers()` + +Return changed lamps since last call. + +`vpx_changed_gi_strings()` + +Return changed lamps since last call. + +`vpx_changed_lamps()` + +Return changed lamps since last call. + +`vpx_changed_leds()` + +Return changed lamps since last call. + +`vpx_changed_solenoids()` + +Return changed solenoids since last call. + +`vpx_get_coilactive(number)` + +Return True if a MPF hw rule for the coil(number) exists. + +`vpx_get_hardwarerules()` + +Return hardware rules. + +`vpx_get_mech(number)` + +Not implemented. + +`vpx_get_switch(number)` + +Return switch value. + +`vpx_mech(number)` + +Not implemented. + +`vpx_pulsesw(number)` + +Pulse switch from VPX. + +`vpx_set_mech(number, value)` + +Not implemented. + +`vpx_set_switch(number, value)` + +Update switch from VPX. + +`vpx_start()` + +Start machine. + +`vpx_switch(number)` + +Return switch value. + diff --git a/docs/code/api_reference/hardware_platforms/visual_pinball_evolution.md b/docs/code/api_reference/hardware_platforms/visual_pinball_evolution.md new file mode 100644 index 0000000000..296b751984 --- /dev/null +++ b/docs/code/api_reference/hardware_platforms/visual_pinball_evolution.md @@ -0,0 +1 @@ +# self.machine.hardware_platforms[‘visual_pinball_evolution’] diff --git a/docs/code/api_reference/index.md b/docs/code/api_reference/index.md new file mode 100644 index 0000000000..48a6f2ded9 --- /dev/null +++ b/docs/code/api_reference/index.md @@ -0,0 +1,17 @@ +# API Reference + +MPF’s API reference is broken into several categories. All of it is presented in the way that the modules and classes are actually used in MPF. + +* [Core Components](api_reference_core.md): MPF core components. + +* [Devices](api_reference_device.md): MPF devices, including physical devices like flippers, ball devices, switches, lights, etc. as well as logical devices like ball saves, extra balls, multiballs, etc. + +* [Modes](api_reference_modes.md): Built-in modes, such as game, attract, tilt, credits, etc. + +* [Platforms](api_reference_hardware_platforms.md): Hardware platforms interfacess for all supported hardware. + +* [Config Players](api_reference_config_players.md): Modules responsible for all config players (show_player, light_player, score_player, etc.) + +* [Tests](api_reference_testing_class_api.md): All unit test base classes for writing tests for MPF and your own game. + +* [Miscellaneous Components](api_reference_misc_components.md): Things that don’t fit into other categories, including utility functions, the base classes for modes, players, timers, and other utility functions. diff --git a/docs/code/api_reference/misc_components/BallSearch.md b/docs/code/api_reference/misc_components/BallSearch.md new file mode 100644 index 0000000000..1707339f59 --- /dev/null +++ b/docs/code/api_reference/misc_components/BallSearch.md @@ -0,0 +1,159 @@ + +# Ball Search + +`class mpf.core.ball_search.BallSearch(machine: mpf.core.machine.MachineController, playfield: Playfield)` + +Bases: mpf.core.mpf_controller.MpfController + +Implements Ball search for a playfield device. + +In MPF, the ball search functionality is attached to each playfield device, rather than being done at the global level. (In other words, each playfield is responsible for making sure no balls get stuck on it, and it leverages an instance of this BallSearch class to handle it.) + +## Methods & Attributes + +The Ball Search has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`block(**kwargs)` + +Block ball search for this playfield. + +Blocking will disable ball search if it’s enabled or running, and will prevent ball search from enabling if it’s disabled until ball_search_unblock() is called. + +`blocked = None` + +If True, ball search will be blocked and will not start. + +`cancel_ball_search(**kwargs)` + +Cancel the current ball search and mark the ball as missing. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`disable(**kwargs)` + +Disable ball search. + +This method will also stop the ball search if it is running. + +`enable(**kwargs)` + +Enable the ball search for this playfield. + +Note that this method does not start the ball search process. Rather it just resets and starts the timeout timer, as well as resetting it when playfield switches are hit. + +`enabled = None` + +Is ball search enabled. + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`give_up()` + +Give up the ball search. + +This method is called when the ball search process Did not find the missing ball. It executes the failed action which depending on the specification of ball_search_failed_action, either adds a replacement ball, ends the game, or ends the current ball. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`iteration = None` + +Current iteration of the ball search, or False if ball search is not started. + +`phase = None` + +Current phase of the ball search, or False if ball search is not started. + +`playfield = None` + +The playfield device this ball search instance is attached to. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`register(priority, callback, name, *, restore_callback=None)` + +Register a callback for sequential ball search. + +Callbacks are called by priority. Ball search only waits if the callback returns true. + +Parameters: + +* **priority** – priority of this callback in the ball search procedure +* **callback** – callback to call. ball search will wait before the next callback, if it returns true +* **name** – string name which is used for debugging & the logs +* **restore_callback** – optional callback to restore state of the device after ball search ended + +`request_to_start_game(**kwargs)` + +Handle result of the request_to_start_game event. + +If ball search is running, this method will return False to prevent the game from starting while ball search is running. + +This method also posts the ball_search_prevents_game_start event if ball search is started. + +`reset_timer()` + +Reset the timeout timer which starts ball search. + +This method will also cancel an actively running (started) ball search. + +This is called by the playfield anytime a playfield switch is hit. + +`start()` + +Start ball search the ball search process. + +`started = None` + +Is the ball search process started (running) now. + +`stop()` + +Stop an actively running ball search. + +`unblock(**kwargs)` + +Unblock ball search for this playfield. + +This will check to see if there are balls on the playfield, and if so, enable ball search. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/misc_components/DataManager.md b/docs/code/api_reference/misc_components/DataManager.md new file mode 100644 index 0000000000..6bfcf3e665 --- /dev/null +++ b/docs/code/api_reference/misc_components/DataManager.md @@ -0,0 +1,74 @@ + +# Data Manager + +`class mpf.core.data_manager.DataManager(machine, name, min_wait_secs=1)` + +Bases: `mpf.core.mpf_controller.MpfController` + +Handles key value data loading and saving for the machine. + +## Methods & Attributes + +The data_manager has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_data(section=None)` + +Return the value of this DataManager’s data. + +Parameters: + +* **section** – Optional string name of a section (dictionary key) for the data you want returned. Default is None which returns the entire dictionary. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`save_all(data)` + +Update all data. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/misc_components/DelayManager.md b/docs/code/api_reference/misc_components/DelayManager.md new file mode 100644 index 0000000000..cb50830c7d --- /dev/null +++ b/docs/code/api_reference/misc_components/DelayManager.md @@ -0,0 +1,141 @@ + +# Delay Manager + +`class mpf.core.delays.DelayManager(machine: MachineController)` + +Bases: `mpf.core.mpf_controller.MpfController` + +Handles delays for one object. + +By default, a machine-wide instance is created and available via self.machine.delay. + +Individual modes also have Delay Managers which can be accessed in mode code via self.delay. (Delays in mode-based delay managers are automatically removed when the mode stops.) + +## Methods & Attributes + +The delay_manager has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`add(ms: int, callback: Callable[[...], None], name: str = None, **kwargs) → str` + +Add a delay. + +Parameters: + +* **ms** – The number of milliseconds you want this delay to be for. +* **callback** – The method that is called when this delay ends. +* **name** – String name of this delay. This name is arbitrary and only used to identify the delay later if you want to remove or change it. If you don’t provide it, a UUID4 name will be created. +* ****kwargs** – Any other (optional) kwarg pairs you pass will be passed along as kwargs to the callback method. + +Returns string name or UUID4 of the delay which you can use to remove it later. + +`add_if_doesnt_exist(ms: int, callback: Callable[[...], None], name: str, **kwargs) → str` + +Add a delay only if a delay with that name doesn’t exist already. + +Parameters: + +* **ms** – Int of the number of milliseconds you want this delay to be for. +* **callback** – The method that is called when this delay ends. +* **name** – String name of this delay. This name is arbitrary and only used to identify the delay later if you want to remove or change it. +* ****kwargs** – Any other (optional) kwarg pairs you pass will be passed along as kwargs to the callback method. + +Returns string name of the delay which you can use to remove it later. + +`check(delay: str) → bool` + +Check to see if a delay exists. + +Parameters: + +* **delay** – A string of the delay you’re checking for. + +Returns true if the delay exists. False otherwise. + +`clear() → None` + +Remove (clear) all the delays associated with this DelayManager. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`remove(name: str)` + +Remove a delay by name. + +Removing a delay prevents the callback from being called and cancels the delay. + +Parameters: + +* **name** – String name of the delay you want to remove. If there is no delay with this name, that’s ok. Nothing happens. + +`reset(ms: int, callback: Callable[[...], None], name: str, **kwargs) → str` + +Reset a delay. + +Resetting will first delete the existing delay (if it exists) and then add new delay with the new settings. If the delay does not exist, that’s ok, and this method is essentially the same as just adding a delay with this name. + +Parameters: + +* **ms** – The number of milliseconds you want this delay to be for. +* **callback** – The method that is called when this delay ends. +* **name** – String name of this delay. This name is arbitrary and only used to identify the delay later if you want to remove or change it. If you don’t provide it, a UUID4 name will be created. +* ****kwargs** – Any other (optional) kwarg pairs you pass will be passed along as kwargs to the callback method. + +Returns string name or UUID4 of the delay which you can use to remove it later. + +`run_now(name: str)` + +Run a delay callback now instead of waiting until its time comes. + +This will cancel the future running of the delay callback. + +Parameters: + +* **name** – Name of the delay to run. If this name is not an active delay, that’s fine. Nothing happens. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/misc_components/DelayManagerRegistry.md b/docs/code/api_reference/misc_components/DelayManagerRegistry.md new file mode 100644 index 0000000000..c7089871c1 --- /dev/null +++ b/docs/code/api_reference/misc_components/DelayManagerRegistry.md @@ -0,0 +1 @@ +# Delay Manager Registry diff --git a/docs/code/api_reference/misc_components/FileManager.md b/docs/code/api_reference/misc_components/FileManager.md new file mode 100644 index 0000000000..1158480ec6 --- /dev/null +++ b/docs/code/api_reference/misc_components/FileManager.md @@ -0,0 +1,36 @@ + +# File Manager + +`class mpf.core.file_manager.FileManager` + +Bases: object + +Manages file interfaces. + +## Methods & Attributes + +The File Manager has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static get_file_interface(filename)` + +Return a file interface. + +`classmethod init()` + +Initialise file interfaces. + +`static load(filename, verify_version=False, halt_on_error=True)` + +Load a file by name. + +`static locate_file(filename) → str` + +Find a file location. +Parameters: filename – Filename to locate + +Returns: Location of file + +`static save(filename, data)` + +Save data to file. + diff --git a/docs/code/api_reference/misc_components/LogMixin.md b/docs/code/api_reference/misc_components/LogMixin.md new file mode 100644 index 0000000000..e65b014358 --- /dev/null +++ b/docs/code/api_reference/misc_components/LogMixin.md @@ -0,0 +1,62 @@ + +# LogMixin + +`class mpf.core.logging.LogMixin` + +Bases: object + +Mixin class to add smart logging functionality to modules. + +## Methods & Attributes + +The LogMixin has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/misc_components/ModeBaseClass.md b/docs/code/api_reference/misc_components/ModeBaseClass.md new file mode 100644 index 0000000000..89361037ec --- /dev/null +++ b/docs/code/api_reference/misc_components/ModeBaseClass.md @@ -0,0 +1,164 @@ + +# Mode base class + +`class mpf.core.mode.Mode(machine: MachineController, config, name: str, path, asset_paths)` + +Bases: mpf.core.logging.LogMixin + +Base class for a mode. + +## Methods & Attributes + +The Mode base class has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`auto_stop_on_ball_end` + +Controls whether this mode is stopped when the ball ends, regardless of its stop_events settings. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`configure_mode_settings(config: dict) → None` + +Process this mode’s configuration settings from a config dictionary. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`delay` + +DelayManager instance for delays in this mode. Note that all delays scheduled here will be automatically canceled when the mode stops. + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`static get_config_spec() → str` + +Return config spec for mode_settings. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_init() → None` + +User-overrideable method which will be called when this mode initializes as part of the MPF boot process. + +`mode_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. whenever it becomes active). + +`mode_stop(**kwargs) → None` + +User-overrideable method which will be called whenever this mode stops. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`player` + +Reference to the current player object. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`restart_on_next_ball` + +Controls whether this mode will restart on the next ball. This only works if the mode was running when the ball ended. It’s tracked per- player in the ‘restart_modes_on_next_ball’ player variable. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/misc_components/Players.md b/docs/code/api_reference/misc_components/Players.md new file mode 100644 index 0000000000..c3aa0383fa --- /dev/null +++ b/docs/code/api_reference/misc_components/Players.md @@ -0,0 +1,87 @@ + +# Players + +`class mpf.core.player.Player(machine, index)` + +Bases: object + +Base class for a player in a game. + +One instance of this class is automatically created for each player. + +The game mode maintains a player attribute which always points to the current player and is available via self.machine.game.player. + +It also contains a player_list attribute which is a list of the player instances (in order) which you can use to access the non-current player. + +This Player class is responsible for tracking player variables which is a dictionary of key/value pairs maintained on a per-player basis. There are several ways they can be used: + +First, player variables can be accessed as attributes of the player object directly. For example, to set a player variable foo for the current player, you could use: + +``` +self.machine.player.foo = 0 +``` + +If that variable didn’t exist, it will be automatically created. + +You can get the value of player variables by accessing them directly. For example: + +``` +print(self.machine.player.foo) # prints 0 +``` + +If you attempt to access a player variable that doesn’t exist, it will automatically be created with a value of 0. + +Every time a player variable is created or changed, an MPF event is posted in the form player_ plus the variable name. For example, creating or changing the foo variable will cause an event called player_foo to be posted. + +The player variable event will have four parameters posted along with it: + +* `value` (the new value) +* `prev_value` (the old value before it was updated) +* `change` (the change in the value) +* `player_num` (the player number the variable belongs to) + +For the change parameter, it will attempt to subtract the old value from the new value. If that works, it will return the result as the change. If it doesn’t work (like if you’re not storing numbers in this variable), then the change parameter will be True if the new value is different and False if the value didn’t change. + +For examples, the following three lines: + +``` +self.machine.player.score = 0 +self.machine.player.score += 500 +self.machine.player.score = 1200 +``` + +will cause the following three events to be posted: + +player_score with Args: value=0, change=0, prev_value=0 player_score with Args: value=500, change=500, prev_value=0 player_score with Args: value=1200, change=700, prev_value=500 + +## Methods & Attributes + +The Players has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`enable_events(enable=True, send_all_variables=True)` + +Enable/disable player variable events. + +Parameters: + +* **enable** – Flag to enable/disable player variable events +* **send_all_variables** – Flag indicating whether or not to send an event with the current value of every player variable. + +`is_player_var(var_name)` + +Check if player var exists. + +Parameters: + +* **var_name** – String name of the player variable to test. + +Returns: True if the variable exists and False if not. + +`monitor_enabled = False` + +Class attribute which specifies whether any monitors have been registered to track player variable changes. + +`send_all_variable_events()` + +Send a player variable event for the current value of all player variables. + diff --git a/docs/code/api_reference/misc_components/RGBAColor.md b/docs/code/api_reference/misc_components/RGBAColor.md new file mode 100644 index 0000000000..633edf53c2 --- /dev/null +++ b/docs/code/api_reference/misc_components/RGBAColor.md @@ -0,0 +1,112 @@ + +# RGBAColor + +`class mpf.core.rgba_color.RGBAColor(color: Union[mpf.core.rgb_color.RGBColor, str, Tuple[int, int, int], Tuple[int, int, int, int], List[int]])` + +Bases: mpf.core.rgb_color.RGBColor + +RGB Color with alpha channel. + +## Methods & Attributes + +The RGBAColor has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static add_color(name: str, color: Union[RGBColor, str, List[int], Tuple[int, int, int]])` + +Add (or updates if it already exists) a color. + +Note that this is not permanent, the list is reset when MPF restarts (though you can define your own custom colors in your config file’s colors: section). You can use this function to dynamically change the values of colors in shows (they take place the next time an LED switches to that color). + +Parameters: + +* **name** – String name of the color you want to add/update +* **color** – The color you want to set. You can pass the same types as the RGBColor class constructor, including a tuple or list of RGB ints (0-255 each), a hex string, an RGBColor instance, or a dictionart of red, green, blue key/value pairs. + +`static blend(start_color, end_color, fraction)` + +Blend two colors. + +Parameters: + +* **start_color** – The start color +* **end_color** – The end color +* **fraction** – The fraction between 0 and 1 that is used to set the blend point between the two colors. + +Returns: An RGBColor object that is a blend between the start and end + + +`blue` + +Return the blue component of the RGB color representation. + +`green` + +Return the green component of the RGB color representation. + +`hex` + +Return a 6-char HEX representation of the color. + +`static hex_to_rgb(hex_string: str, default=None) → Tuple[int, int, int]` + +Convert a HEX color representation to an RGB color representation. + +Parameters: + +* **hex_string** – The 3- or 6-char hexadecimal string representing the color value. +* **default** – The default value to return if _hex is invalid. + +Returns: RGB representation of the input HEX value as a 3-item tuple +with each item being an integer 0-255. + +`name` + +Return the color name or None. + +Returns a string containing a standard color name or None if the current RGB color does not have a standard name. + +`static name_to_rgb(name: str, default=(0, 0, 0)) → Tuple[int, int, int]` + +Convert a standard color name to an RGB value (tuple). + +If the name is not found, the default value is returned. :param name: A standard color name. :param default: The default value to return if the color name is not found. :return: RGB representation of the named color. :rtype: tuple + +`static random_rgb() → Tuple[int, int, int]` + +Generate a uniformly random RGB value. +Returns: A tuple of three integers with values between 0 and 255 inclusive + +`red` + +Return the red component of the RGB color representation. + +`rgb` + +Return an RGB representation of the color. + +`static rgb_to_hex(rgb: Tuple[int, int, int]) → str` + +Convert an RGB color representation to a HEX color representation. + +``` +(r, g, b) :: r -> [0, 255] +g -> [0, 255] b -> [0, 255] +``` + +Parameters: + +* **rgb** – A tuple of three numeric values corresponding to the red, green, and blue value. + +Returns: HEX representation of the input RGB value. +Return type: str + +`rgba` + +Return an RGB representation of the color. + +`static string_to_rgb(value: str, default=(0, 0, 0)) → Tuple[int, int, int]` + +Convert a string which could be either a standard color name or a hex value to an RGB value (tuple). + +If the name is not found and the supplied value is not a valid hex string it raises an error. :param value: A standard color name or hex value. :param default: The default value to return if the color name is not found and the supplied value is not a valid hex color string. :return: RGB representation of the named color. :rtype: tuple + diff --git a/docs/code/api_reference/misc_components/RGBColor.md b/docs/code/api_reference/misc_components/RGBColor.md new file mode 100644 index 0000000000..38599ee3ff --- /dev/null +++ b/docs/code/api_reference/misc_components/RGBColor.md @@ -0,0 +1,108 @@ + +# RGBColor + +`class mpf.core.rgb_color.RGBColor(color: Union[RGBColor, str, List[int], Tuple[int, int, int]] = None)` + +Bases: object + +One RGB Color. + +## Methods & Attributes + +The RGBColor has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static add_color(name: str, color: Union[RGBColor, str, List[int], Tuple[int, int, int]])` + +Add (or updates if it already exists) a color. + +Note that this is not permanent, the list is reset when MPF restarts (though you can define your own custom colors in your config file’s colors: section). You can use this function to dynamically change the values of colors in shows (they take place the next time an LED switches to that color). + +Parameters: + +* **name** – String name of the color you want to add/update +* **color** – The color you want to set. You can pass the same types as the RGBColor class constructor, including a tuple or list of RGB ints (0-255 each), a hex string, an RGBColor instance, or a dictionart of red, green, blue key/value pairs. + +`static blend(start_color, end_color, fraction)` + +Blend two colors. + +Parameters: + +* **start_color** – The start color +* **end_color** – The end color +* **fraction** – The fraction between 0 and 1 that is used to set the blend point between the two colors. + +Returns: An RGBColor object that is a blend between the start and end + + +`blue` + +Return the blue component of the RGB color representation. + +`green` + +Return the green component of the RGB color representation. + +`hex` + +Return a 6-char HEX representation of the color. + +`static hex_to_rgb(hex_string: str, default=None) → Tuple[int, int, int]` + +Convert a HEX color representation to an RGB color representation. + +Parameters: + +* **hex_string** – The 3- or 6-char hexadecimal string representing the color value. +* **default** – The default value to return if _hex is invalid. + +Returns: RGB representation of the input HEX value as a 3-item tuple +with each item being an integer 0-255. + +`name` + +Return the color name or None. + +Returns a string containing a standard color name or None if the current RGB color does not have a standard name. + +`static name_to_rgb(name: str, default=(0, 0, 0)) → Tuple[int, int, int]` + +Convert a standard color name to an RGB value (tuple). + +If the name is not found, the default value is returned. :param name: A standard color name. :param default: The default value to return if the color name is not found. :return: RGB representation of the named color. :rtype: tuple + +`static random_rgb() → Tuple[int, int, int]` + +Generate a uniformly random RGB value. +Returns: A tuple of three integers with values between 0 and 255 inclusive + +`red + +Return the red component of the RGB color representation. + +`rgb +` +Return an RGB representation of the color. + +`static rgb_to_hex(rgb: Tuple[int, int, int]) → str` + +Convert an RGB color representation to a HEX color representation. + +``` +(r, g, b) :: r -> [0, 255] +g -> [0, 255] b -> [0, 255] +``` + +Parameters: + +* **rgb** – A tuple of three numeric values corresponding to the red, green, and blue value. + +Returns: HEX representation of the input RGB value. +Return type: str + +`static string_to_rgb(value: str, default=(0, 0, 0)) → Tuple[int, int, int]` + +Convert a string which could be either a standard color name or a hex value to an RGB value (tuple). + +If the name is not found and the supplied value is not a valid hex string it raises an error. :param value: A standard color name or hex value. :param default: The default value to return if the color name is not found and the supplied value is not a valid hex color string. :return: RGB representation of the named color. :rtype: tuple + diff --git a/docs/code/api_reference/misc_components/Randomizer.md b/docs/code/api_reference/misc_components/Randomizer.md new file mode 100644 index 0000000000..09e6b0d2d9 --- /dev/null +++ b/docs/code/api_reference/misc_components/Randomizer.md @@ -0,0 +1,31 @@ +# Randomizer + +`class mpf.core.randomizer.Randomizer(items)` + +Bases: `object` + +Generic list randomizer. + +## Methods & Attributes + +The Randomizer has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`get_current()` + +Return current item. + +`get_next()` + +Return next item. + +`loop` + +Return loop property. + +`static pick_weighted_random(items)` + +Pick a random item. + +Parameters: + +* **items** – Items to select from diff --git a/docs/code/api_reference/misc_components/Timers.md b/docs/code/api_reference/misc_components/Timers.md new file mode 100644 index 0000000000..dc162cd13a --- /dev/null +++ b/docs/code/api_reference/misc_components/Timers.md @@ -0,0 +1 @@ +Timers diff --git a/docs/code/api_reference/misc_components/UtilityFunctions.md b/docs/code/api_reference/misc_components/UtilityFunctions.md new file mode 100644 index 0000000000..eda62bf5c2 --- /dev/null +++ b/docs/code/api_reference/misc_components/UtilityFunctions.md @@ -0,0 +1,286 @@ + +# Utility Functions + +`class mpf.core.utility_functions.Util` + +Bases: object + +Utility functions for MPF. + +## Methods & Attributes + +The Utility Functions has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static any(futures: Iterable[_asyncio.Future], loop, timeout=None)` + +Return first future. + +`static bin_str_to_hex_str(source_int_str: str, num_chars: int) → str` + +Convert binary string to hex string. + +`static cancel_futures(futures: Iterable[_asyncio.Future])` + +Cancel futures. + +`static chunker(l, n)` + +Yield successive n-sized chunks from l. + +`static convert_to_simply_type(value)` + +Convert value to a simple type. + +`static convert_to_type(value, type_name)` + +Convert value to type. + +`static db_to_gain(db: float) → float` + +Convert a value in decibels (-inf to 0.0) to a gain (0.0 to 1.0). + +Parameters: + +* **db** – The decibel value (float) to convert to a gain + +Returns float. + +`static dict_merge(a, b, combine_lists=True) → dict` + +Recursively merge dictionaries. + +Used to merge dictionaries of dictionaries, like when we’re merging together the machine configuration files. This method is called recursively as it finds sub-dictionaries. + +For example, in the traditional python dictionary update() methods, if a dictionary key exists in the original and merging-in dictionary, the new value will overwrite the old value. + +Consider the following example: + +Original dictionary: config[‘foo’][‘bar’] = 1 + +New dictionary we’re merging in: config[‘foo’][‘other_bar’] = 2 + +Default python dictionary update() method would have the updated dictionary as this: + +``` +{‘foo’: {‘other_bar’: 2}} +``` + +This happens because the original dictionary which had the single key bar was overwritten by a new dictionary which has a single key other_bar.) + +But really we want this: + +``` +{‘foo’: {‘bar’: 1, ‘other_bar’: 2}} +``` + +This code was based on this: https://www.xormedia.com/recursively-merge-dictionaries-in-python/ + +Parameters: + +* **a (dict)** – The first dictionary +* **b (dict)** – The second dictionary +* **combine_lists (bool)** – Controls whether lists should be combined (extended) or overwritten. Default is True which combines them. + +Returns the merged dictionaries. + +`static event_config_to_dict(config) → dict` + +Convert event config to a dict. + +`static first(futures: Iterable[_asyncio.Future], loop, timeout=None, cancel_others=True)` + +Return first future and cancel others. + +`static get_from_dict(dic, key_path)` + +Get a value from a nested dict (or dict-like object) from an iterable of key paths. + +Parameters: + +* **dic** – Nested dict of dicts to get the value from. +* **key_path** – iterable of key paths + +Returns the value from the dict. + +This code came from here: http://stackoverflow.com/questions/14692690/access-python-nested-dictionary-items-via-a-list-of-keys + +`static get_named_list_from_objects(switches) → List[str]` + +Return a list of names from a list of switch objects. + +`static hex_string_to_int(inputstring: str, maxvalue: int = 255) → int` + +Take a string input of hex numbers and an integer. + +Parameters: + +* **inputstring** – A string of incoming hex colors, like ffff00. +* **maxvalue** – Integer of the max value you’d like to return. Default is 255. (This is the real value of why this method exists.) + +Returns integer representation of the hex string. + +`static hex_string_to_list(input_string, output_length=3) → List[int]` + +Take a string input of hex numbers and return a list of integers. + +This always groups the hex string in twos, so an input of ffff00 will be returned as [255, 255, 0]. + +Parameters: + +* **input_string** – A string of incoming hex colors, like ffff00. +* **output_length** – Integer value of the number of items you’d like in your returned list. Default is 3. This method will ignore extra characters if the input_string is too long, and it will pad the left with zeros if the input string is too short. + +Returns list of integers, like [255, 255, 0]. + +Raises ValueError if the input string contains non-hex chars. + +`static int_to_hex_string(source_int: int) → str` + +Convert an int from 0-255 to a one-byte (2 chars) hex string, with uppercase characters. + +`static is_hex_string(string: str) → bool` + +Return true if string is hex. + +`static is_power2(num: int) → bool` + +Check a number to see if it’s a power of two. + +Parameters: + +* **num** – The number to check + +Returns True or False. + +`static keys_to_lower(source_dict) → Union[dict, list]` + +Convert the keys of a dictionary to lowercase. + +Parameters: + +* **source_dict** – The dictionary you want to convert. + +Returns a dictionary with lowercase keys. + +`static list_of_lists(incoming_string)` + +Convert an incoming string or list into a list of lists. + +`static normalize_hex_string(source_hex: str, num_chars: int = 2) → str` + +Take an incoming hex value and convert it to uppercase and fills in leading zeros. + +Parameters: + +* **source_hex** – Incoming source number. Can be any format. +* **num_chars** – Total number of characters that will be returned. Default is two. + +Returns string, uppercase, zero padded to the num_chars. + +Example usage: Send “c” as source_hex, returns “0C”. + +`static power_to_on_off(power: float, max_period: int = 20) → Tuple[int, int]` + +Convert a float value to on/off times. + +`static pwm32_to_hex_string(source_int: int) → str` + +Convert a PWM32 value to hex. + +`static pwm32_to_int(source_int: int) → int` + +Convert a PWM32 value to int. + +`static pwm8_to_hex_string(source_int: int) → str` + +Convert an int to a PWM8 string. + +`static pwm8_to_int(source_int: int) → int` + +Convert a PWM8 value to int. + +`static race(futures: Dict[_asyncio.Future, str], loop)` + +Return key of first future and cancel others. + +`static raise_exceptions(future: _asyncio.Future) → None` + +Re-raise any error except CancelledError on this exception. + +Use this with add_done_callback on any future which is not awaited directly to prevent swallowed exceptions. + +`static set_in_dict(dic, key_path, value)` + +Set a value in a nested dict-like object based on an iterable of nested keys. + +Parameters: + +* **dic** – Nested dict of dicts to set the value in. +* **key_path** – Iterable of the path to the key of the value to set. +* **value** – Value to set. + +`static string_to_class(class_string: str) → Callable[[...], Any]` + +Convert a string like mpf.core.events.EventManager into a Python class. + +Parameters: + +* **class_string (str)** – The input string + +Returns a reference to the python class object. + +This function came from here: http://stackoverflow.com/questions/452969/does-python-have-an-equivalent-to-java-class-forname + +`static string_to_event_list(string: Union[str, List[str], None]) → List[Any]` + +Convert a comma-separated and/or space-separated event string into a Python list if not already a list. + +This version honors placeholders/templates for events. + +Parameters: + +* **string** – The string you’d like to convert. + +Returns a python list object containing whatever was between commas in the string. + +`static string_to_gain(gain_string: str) → float` + +Convert string to gain. + +Decode a string containing either a gain value (0.0 to 1.0) or a decibel value (-inf to 0.0) into a gain value (0.0 to 1.0). + +Parameters: + +* **gain_string** – The string to convert to a gain value + +Returns float containing a gain value (0.0 to 1.0). + +`static string_to_list(string: Union[str, List[str], None]) → List[Any]` + +Convert a comma-separated string into a Python list if not already a list. + +Parameters: + +* **string** – The string you’d like to convert. + +Returns a python list object containing whatever was between commas in the string. + +`static string_to_ms(time_string: str) → int` + +Decode a string of real-world time into an int of milliseconds. + +Example inputs: + +200ms 2s None + +If no “s” or “ms” is provided, this method assumes “milliseconds.” + +If time is ‘None’ or a string of ‘None’, this method returns 0. + +Returns an integer. The examples listed above return 200, 2000 and 0, respectively. + +`static string_to_secs(time_string: str) → float` + +Decode a string of real-world time into an float of seconds. + +See ‘string_to_ms’ for a description of the time string. diff --git a/docs/code/api_reference/modes/attract.md b/docs/code/api_reference/modes/attract.md new file mode 100644 index 0000000000..c11b65bd09 --- /dev/null +++ b/docs/code/api_reference/modes/attract.md @@ -0,0 +1,160 @@ + +# self.machine.modes.attract + +`class mpf.modes.attract.code.attract.Attract(*args, **kwargs)` + +Bases: mpf.core.mode.Mode + +Default mode running in a machine when a game is not in progress. + +The attract mode’s main job is to watch for the start button to be pressed, to post the requests to start games, and to move the machine flow to the next mode if the request to start game comes back as approved. + +## Accessing the attract mode via code + +You can access the attract mode from anywhere via `self.machine.modes.attract`. + +## Methods & Attributes + +The attract mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`result_of_start_request(ev_result=True)` + +Handle the result of the start request. + +Called after the request_to_start_game event is posted. + +If result is True, this method posts the event game_start. If False, nothing happens, as the game start request was denied by some handler. + +Parameters: ev_result – Bool result of the boolean event request_to_start_game. If any registered event handler did not want the game to start, this will be False. Otherwise it’s True. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`start_button_pressed()` + +Handle start button press. + +Called when the a switch tagged with start is activated. + +Note that in MPF, the game start process is initiated when the start button is released, so when the button is first pressed, MPF just records the time stamp. This allows the total time the start button was pressed to be note, so that, for example, different types of games can be started based on long-presses of the start button. + +`start_button_released(**kwargs)` + +Handle start button release. + +Called when the a switch tagged with start is deactivated. + +Since this is the Attract mode, this method posts a boolean event called request_to_start_game. If that event comes back True, this method calls result_of_start_request(). + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/bonus.md b/docs/code/api_reference/modes/bonus.md new file mode 100644 index 0000000000..56efb20189 --- /dev/null +++ b/docs/code/api_reference/modes/bonus.md @@ -0,0 +1,140 @@ + +# self.machine.modes.bonus + +`class mpf.modes.bonus.code.bonus.Bonus(*args, **kwargs)` + +Bases: mpf.core.mode.Mode + +Bonus mode for MPF. + +Give a player bonus for their achievements, but only if the machine is not tilted. + +## Accessing the bonus mode via code + +You can access the bonus mode from anywhere via `self.machine.modes.bonus`. + +## Methods & Attributes + +The bonus mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`hurry_up(**kwargs)` + +Change the slide display delay to the “hurry up” setting. + +This is typically used with a flipper cancel event to hurry up the bonus display when the player hits both flippers. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/carousel.md b/docs/code/api_reference/modes/carousel.md new file mode 100644 index 0000000000..952253ccb9 --- /dev/null +++ b/docs/code/api_reference/modes/carousel.md @@ -0,0 +1,132 @@ + +# self.machine.modes.carousel + +`class mpf.modes.carousel.code.carousel.Carousel(*args, **kwargs)` + +Bases: mpf.core.mode.Mode + +Mode which allows the player to select another mode to run. + +## Accessing the carousel mode via code + +You can access the carousel mode from anywhere via `self.machine.modes.carousel`. + +## Methods & Attributes + +The carousel mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/credits.md b/docs/code/api_reference/modes/credits.md new file mode 100644 index 0000000000..c6f60fd13e --- /dev/null +++ b/docs/code/api_reference/modes/credits.md @@ -0,0 +1,152 @@ + +# self.machine.modes.credits + +class mpf.modes.credits.code.credits.Credits(*args, **kwargs) + +Bases: mpf.core.mode.Mode + +Mode which manages the credits and prevents the game from starting without credits. + +## Accessing the credits mode via code + +You can access the credits mode from anywhere via `self.machine.modes.credits`. + +## Methods & Attributes + +The credits mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_credit(price_tiering=True)` + +Add a single credit to the machine. +Parameters: price_tiering – Boolean which controls whether this credit will be eligible for the pricing tier bonuses. Default is True. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`clear_all_credits(**kwargs) + +Clear all credits. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`enable_credit_play(post_event=True, **kwargs)` + +Enable credits play. + +`enable_free_play(post_event=True, **kwargs)` + +Enable free play. + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`toggle_credit_play(**kwargs)` + +Toggle between free and credits play. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/game.md b/docs/code/api_reference/modes/game.md new file mode 100644 index 0000000000..ed9428343e --- /dev/null +++ b/docs/code/api_reference/modes/game.md @@ -0,0 +1,198 @@ + +# self.machine.modes.game + +`class mpf.modes.game.code.game.Game(*args, **kwargs)` + +Bases: mpf.core.async_mode.AsyncMode + +Base mode that runs an active game on a pinball machine. + +The game mode is responsible for creating players, starting and ending balls, rotating to the next player, etc. + +## Accessing the game mode via code + +You can access the game mode from anywhere via `self.machine.modes.game`. + +## Methods & Attributes + +The game mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`ball_drained(balls=0, **kwargs)` + +One or more balls has drained. + +Drained balls will be subtracted from the number of balls in play. + +Parameters: + +* **balls** – The number of balls that just drained. + +Returns a dictionary: {balls: number of balls drained}. + +`ball_ending()` + +Handle ball ending. + +DEPRECATED in v0.50. Use end_ball() instead. + +`balls_in_play` + +Property which holds the current number of balls in play. + +Note that the number of balls in play is not necessarily the same as the number of balls that are active on the playfield. (For example, a ball could be held in a device while a show is playing, etc.) + +You can set this property to change it, or get it’s value. + +If you set this value to 0, the ball ending process will be started. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`end_ball()` + +Set an event flag that will end the current ball. + +`end_game()` + +End the current game. + +This triggers the game end manually. + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`event_end_ball(**kwargs)` + +Event handler to end the current ball. + +`event_end_game(**kwargs)` + +Event handler to end the current game. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`game_ending() + +Handle game ending. + +DEPRECATED in v0.50. Use end_game() instead. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return false. + +We are the game and not a mode within the game. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`request_player_add(**kwargs)` + +Request to add a player to an active game. + +This method contains the logic to verify whether it’s ok to add a player. For example, the game must be on Ball 1 and the current number of players must be less than the max number allowed. + +Assuming this method believes it’s ok to add a player, it posts the boolean event player_add_request to give other modules the opportunity to deny it. For example, a credits module might deny the request if there are not enough credits in the machine. + +If player_add_request comes back True, the event player_added is posted with a reference to the new player object as a player kwarg. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/high_score.md b/docs/code/api_reference/modes/high_score.md new file mode 100644 index 0000000000..40cd648775 --- /dev/null +++ b/docs/code/api_reference/modes/high_score.md @@ -0,0 +1,134 @@ + +# self.machine.modes.high_score + +`class mpf.modes.high_score.code.high_score.HighScore(*args, **kwargs)` + +Bases: mpf.core.async_mode.AsyncMode + +High score mode. + +Mode which runs during the game ending process to check for high scores and lets the players enter their names or initials. + +## Accessing the high_score mode via code + +You can access the high_score mode from anywhere via `self.machine.modes.high_score`. + +## Methods & Attributes + +The high_score mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode.` + +`load_mode_devices() → None + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/match.md b/docs/code/api_reference/modes/match.md new file mode 100644 index 0000000000..de6714e8c6 --- /dev/null +++ b/docs/code/api_reference/modes/match.md @@ -0,0 +1,132 @@ + +# self.machine.modes.match + +`class mpf.modes.match.code.match.Match(*args, **kwargs)` + +Bases: mpf.core.async_mode.AsyncMode + +Match mode. + +## Accessing the match mode via code + +You can access the match mode from anywhere via `self.machine.modes.match`. + +## Methods & Attributes + +The match mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/service.md b/docs/code/api_reference/modes/service.md new file mode 100644 index 0000000000..376a3fd3de --- /dev/null +++ b/docs/code/api_reference/modes/service.md @@ -0,0 +1,132 @@ + +# self.machine.modes.service + +`class mpf.modes.service.code.service.Service(*args, **kwargs)` + +Bases: mpf.core.async_mode.AsyncMode + +The service mode. + +## Accessing the service mode via code + +You can access the service mode from anywhere via `self.machine.modes.service`. + +## Methods & Attributes + +The service mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/modes/tilt.md b/docs/code/api_reference/modes/tilt.md new file mode 100644 index 0000000000..2096b99772 --- /dev/null +++ b/docs/code/api_reference/modes/tilt.md @@ -0,0 +1,162 @@ + +# self.machine.modes.tilt + +`class mpf.modes.tilt.code.tilt.Tilt(*args, **kwargs)` + +Bases: mpf.core.mode.Mode + +A mode which handles a tilt in a pinball machine. + +Note that this mode is always running (even during attract mode) since the machine needs to watch for slam tilts at all times. + +## Accessing the tilt mode via code + +You can access the tilt mode from anywhere via `self.machine.modes.tilt`. + +## Methods & Attributes + +The tilt mode has the following methods & attributes available. Note that methods & attributes inherited from the base Mode class are not included here. + +`active` + +Return True if this mode is active. + +`add_mode_event_handler(event: str, handler: Callable, priority: int = 0, **kwargs) → mpf.core.events.EventHandlerKey` + +Register an event handler which is automatically removed when this mode stops. + +This method is similar to the Event Manager’s add_handler() method, except this method automatically unregisters the handlers when the mode ends. + +Parameters: + +* **event** – String name of the event you’re adding a handler for. Since events are text strings, they don’t have to be pre-defined. +* **handler** – The method that will be called when the event is fired. +* **priority** – An arbitrary integer value that defines what order the handlers will be called in. The default is 1, so if you have a handler that you want to be called first, add it here with a priority of 2. (Or 3 or 10 or 100000.) The numbers don’t matter. They’re called from highest to lowest. (i.e. priority 100 is called before priority 1.) +* ****kwargs** – Any any additional keyword/argument pairs entered here will be attached to the handler and called whenever that handler is called. Note these are in addition to kwargs that could be passed as part of the event post. If there’s a conflict, the event-level ones will win. + +Returns a EventHandlerKey to the handler which you can use to later remove the handler via remove_handler_by_key. Though you don’t need to remove the handler since the whole point of this method is they’re automatically removed when the mode stops. + +Note that if you do add a handler via this method and then remove it manually, that’s ok too. + +`configure_logging(logger: str, console_level: str = 'basic', file_level: str = 'basic', url_base=None)` + +Configure logging. + +Parameters: + +* **logger** – The string name of the logger to use. +* **console_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **file_level** – The level of logging for the console. Valid options are “none”, “basic”, or “full”. +* **url_base** – Base URL for docs links in exceptions. + +`create_mode_devices() → None` + +Create new devices that are specified in a mode config that haven’t been created in the machine-wide. + +`debug_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the debug level. + +Note that whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`error_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the error level. + +These messages will always be shown in the console and the log file. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`info_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the info level. + +Whether this message shows up in the console or log file is controlled by the settings used with configure_logging(). + +`initialise_mode() → None` + +Initialise this mode. + +`is_game_mode` + +Return true if this is a game mode. + +`load_mode_devices() → None` + +Load config of mode devices. + +`mode_will_start(**kwargs) → None` + +User-overrideable method which will be called whenever this mode starts (i.e. before it becomes active). + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`reset_warnings(**kwargs)` + +Reset the tilt warnings for the current player. + +`slam_tilt(**kwargs)` + +Process a slam tilt. + +This method posts the slam_tilt event and (if a game is active) sets the game mode’s slam_tilted attribute to True. + +`start(mode_priority=None, callback=None, **kwargs) → None` + +Start this mode. + +Parameters: + +* **mode_priority** – Integer value of what you want this mode to run at. If you don’t specify one, it will use the “Mode: priority” setting from this mode’s configuration file. +* **callback** – Callback to call when this mode has been started. +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode starts in the mode_start method which will be called automatically. + +`stop(callback: Any = None, **kwargs) → bool` + +Stop this mode. + +Parameters: + +* **callback** – Method which will be called once this mode has stopped. Will only be called when the mode is running (includes currently stopping) +* ****kwargs** – Catch-all since this mode might start from events with who-knows-what keyword arguments. + +Warning: You can safely call this method, but do not override it in your mode code. If you want to write your own mode code by subclassing Mode, put whatever code you want to run when this mode stops in the mode_stop method which will be called automatically. + +Returns true if the mode is running. Otherwise false. + +`tilt(**kwargs)` + +Cause the ball to tilt. + +This will post an event called tilt, set the game mode’s tilted attribute to True, disable the flippers and autofire devices, end the current ball, and wait for all the balls to drain. + +`tilt_settle_ms_remaining()` + +Return the amount of milliseconds remaining until the tilt settle time has cleared. + +Returns an integer of the number of ms remaining until tilt settled is cleared. + +`tilt_warning(**kwargs)` + +Process a tilt warning. + +If the number of warnings is the number to cause a tilt, a tilt will be processed. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/testing_class_api/MockBcpClient.md b/docs/code/api_reference/testing_class_api/MockBcpClient.md new file mode 100644 index 0000000000..da43cc2a22 --- /dev/null +++ b/docs/code/api_reference/testing_class_api/MockBcpClient.md @@ -0,0 +1,56 @@ + +# MockBcpClient + +`class mpf.tests.MpfBcpTestCase.MockBcpClient(machine, name, bcp)` + +Bases: `mpf.core.bcp.bcp_client.BaseBcpClient` + +A Mock BCP Client. + +This is used in tests require BCP for testing but where you don’t actually create a real BCP connection. + +## Methods & Attributes + +The MockBcpClient has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`accept_connection(receiver, sender)` + +Handle incoming connection from remote client. + +`connect(config)` + +Actively connect client. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`read_message()` + +Read one message from client. + +`send(bcp_command, bcp_command_args)` + +Send data to client. + +`stop()` + +Stop client connection. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + + diff --git a/docs/code/api_reference/testing_class_api/MpfBcpTestCase.md b/docs/code/api_reference/testing_class_api/MpfBcpTestCase.md new file mode 100644 index 0000000000..961c064dbc --- /dev/null +++ b/docs/code/api_reference/testing_class_api/MpfBcpTestCase.md @@ -0,0 +1,662 @@ + +# MpfBcpTestCase + +`class mpf.tests.MpfBcpTestCase.MpfBcpTestCase(methodName='runTest')` + +Bases: `mpf.tests.MpfTestCase.MpfTestCase` + +An MpfTestCase instance which uses the MockBcpClient. + +## Methods & Attributes + +The MpfBcpTestCase has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static add_to_config_validator(machine, key, new_dict)` + +Add config dict to validator. + +`advance_time_and_run(delta=1.0)` + +Advance the test clock and run anything that should run during that time. + +Parameters: + +* **delta** – How much time to advance the test clock by (in seconds) + +This method will cause anything scheduled during the time to run, including things like delays, timers, etc. + +Advancing the clock will happen in multiple small steps if things are scheduled to happen during this advance. For example, you can advance the clock 10 seconds like this: + +``` +self.advance_time_and_run(10) +``` + +If there is a delay callback that is scheduled to happen in 2 seconds, then this method will advance the clock 2 seconds, process that delay, and then advance the remaining 8 seconds. + +`assertAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are unequal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is more than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +If the two objects compare equal then they will automatically compare almost equal. + +`assertAvailableBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is available on a playfield. + +`assertBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is on a playfield. + +`assertColorAlmostEqual(color1, color2, delta=6)` + +Assert that two color are almost equal. + +Parameters: + +* **color1** – The first color, as an RGBColor instance or 3-item iterable. +* **color2** – The second color, as an RGBColor instance or 3-item iterable. +* **delta** – How close the colors have to be. The deltas between red, green, and blue are added together and must be less or equal to this value for this assertion to succeed. + +`assertCountEqual(first, second, msg=None)` + +An unordered sequence comparison asserting that the same elements, regardless of order. If the same element occurs more than once, it verifies that the elements occur the same number of times. + +``` +self.assertEqual(Counter(list(first)), + Counter(list(second))) +``` + +Example: +``` +[0, 1, 1] and [1, 0, 1] compare equal. +[0, 0, 1] and [0, 1] compare unequal. +``` + +`assertDictContainsSubset(subset, dictionary, msg=None)` + +Checks whether dictionary is a superset of subset. + +`assertEqual(first, second, msg=None)` + +Fail if the two objects are unequal as determined by the ‘==’ operator. + +`assertEventCalled(event_name, times=None)` + +Assert that event was called. + +Parameters: + +* **event_name** – String name of the event to check. +* **times** – An optional value to confirm the number of times the event was called. Default of None means this method will pass as long as the event has been called at least once. + +If you want to reset the times count, you can mock the event again. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 1) # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 2) # This will pass +``` + +`assertEventCalledWith(event_name, **kwargs)` + +Assert an event was called with certain kwargs. + +Parameters: + +* **event_name** – String name of the event to check. +* ****kwargs** – Name/value parameters to check. + +For example: + +``` +self.mock_event('jackpot') + +self.post_event('jackpot', count=1, first_time=True) +self.assertEventCalled('jackpot') # This will pass +self.assertEventCalledWith('jackpot', count=1, first_time=True) # This will also pass +self.assertEventCalledWith('jackpot', count=1, first_time=False) # This will fail +``` + +`assertEventNotCalled(event_name)` + +Assert that event was not called. + +Parameters: + +* **event_name** – String name of the event to check. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +`assertFalse(expr, msg=None)` + +Check that the expression is false. + +`assertGreater(a, b, msg=None)` + +Just like self.assertTrue(a > b), but with a nicer default message. + +`assertGreaterEqual(a, b, msg=None)` + +Just like self.assertTrue(a >= b), but with a nicer default message. + +`assertIn(member, container, msg=None)` + +Just like self.assertTrue(a in b), but with a nicer default message. + +`assertIs(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is b), but with a nicer default message. + +`assertIsInstance(obj, cls, msg=None)` + +Same as self.assertTrue(isinstance(obj, cls)), with a nicer default message. + +`assertIsNone(obj, msg=None)` + +Same as self.assertTrue(obj is None), with a nicer default message. + +`assertIsNot(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is not b), but with a nicer default message. + +`assertIsNotNone(obj, msg=None)` + +Included for symmetry with assertIsNone. + +`assertLess(a, b, msg=None)` + +Just like self.assertTrue(a < b), but with a nicer default message. + +`assertLessEqual(a, b, msg=None)` + +Just like self.assertTrue(a <= b), but with a nicer default message. + +`assertLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel has a certain brightness. + +`assertLightColor(light_name, color)` + +Assert that a light exists and shows one color. + +`assertLightColors(light_name, color_list, secs=1, check_delta=0.1)` + +Assert that a light exists and shows all colors in a list over a period. + +`assertLightFlashing(light_name, color=None, secs=1, check_delta=0.1)` + +Assert that a light exists and is flashing. + +`assertLightOff(light_name)` + +Assert that a light exists and is off. + +`assertLightOn(light_name)` + +Assert that a light exists and is on. + +`assertListEqual(list1, list2, msg=None)` + +A list-specific equality assertion. + +Parameters: + +* **list1** – The first list to compare. +* **list2** – The second list to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertLogs(logger=None, level=None)` + +Fail unless a log message of level level or higher is emitted on logger_name or its children. If omitted, level defaults to INFO and logger defaults to the root logger. + +This method must be used as a context manager, and will yield a recording object with two attributes: output and records. At the end of the context manager, the output attribute will be a list of the matching formatted log messages and the records attribute will be a list of the corresponding LogRecord objects. + +Example: + +``` +with self.assertLogs('foo', level='INFO') as cm: + logging.getLogger('foo').info('first message') + logging.getLogger('foo.bar').error('second message') +self.assertEqual(cm.output, ['INFO:foo:first message', + 'ERROR:foo.bar:second message']) +``` + +`assertMachineVarEqual(value, machine_var)` + +Assert that a machine variable exists and has a certain value. + +`assertModeNotRunning(mode_name)` + +Assert that a mode exists and is not running. + +`assertModeRunning(mode_name)` + +Assert that a mode exists and is running. + +`assertMultiLineEqual(first, second, msg=None)` + +Assert that two multi-line strings are equal. + +`assertNotAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are equal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is less than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +Objects that are equal automatically fail. + +`assertNotEqual(first, second, msg=None)` + +Fail if the two objects are equal as determined by the ‘!=’ operator. + +`assertNotIn(member, container, msg=None)` + +Just like self.assertTrue(a not in b), but with a nicer default message. + +`assertNotIsInstance(obj, cls, msg=None)` + +Included for symmetry with assertIsInstance. + +`assertNotLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel does not have a certain brightness. + +`assertNotLightColor(light_name, color)` + +Assert that a light exists and does not show a certain color. + +`assertNotRegex(text, unexpected_regex, msg=None)` + +Fail the test if the text matches the regular expression. + +`assertNumBallsKnown(balls)` + +Assert that a certain number of balls are known in the machine. + +`assertPlaceholderEvaluates(expected, condition)` + +Assert that a placeholder evaluates to a certain value. + +`assertPlayerVarEqual(value, player_var)` + +Assert that a player variable exists and has a certain value. + +`assertRaises(expected_exception, *args, **kwargs)` + +Fail unless an exception of class expected_exception is raised by the callable when invoked with specified positional and keyword arguments. If a different type of exception is raised, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertRaises(SomeException): + do_something() +``` +An optional keyword argument ‘msg’ can be provided when assertRaises is used as a context object. + +The context manager keeps a reference to the exception as the ‘exception’ attribute. This allows you to inspect the exception after the assertion: + +``` +with self.assertRaises(SomeException) as cm: + do_something() +the_exception = cm.exception +self.assertEqual(the_exception.error_code, 3) +``` + +`assertRaisesRegex(expected_exception, expected_regex, *args, **kwargs)` + +Asserts that the message in a raised exception matches a regex. + +Parameters: + +* **expected_exception** – Exception class expected to be raised. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertRaisesRegex is used as a context manager. + +`assertRegex(text, expected_regex, msg=None)` + +Fail the test unless the text matches the regular expression. + +`assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)` + +An equality assertion for ordered sequences (like lists and tuples). + +For the purposes of this function, a valid ordered sequence type is one which can be indexed, has a length, and has an equality operator. + +Parameters: + +* **seq1** – The first sequence to compare. +* **seq2** – The second sequence to compare. +* **seq_type** – The expected datatype of the sequences, or None if no datatype should be enforced. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertSetEqual(set1, set2, msg=None)` + +A set-specific equality assertion. + +Parameters: + +* **set1** – The first set to compare. +* **set2** – The second set to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +assertSetEqual uses ducktyping to support different types of sets, and is optimized for sets specifically (parameters must support a difference method). + +`assertSwitchState(name, state)` + +Assert that a switch exists and has a certain state. + +`assertTrue(expr, msg=None)` + +Check that the expression is true. + +`assertTupleEqual(tuple1, tuple2, msg=None)` + +A tuple-specific equality assertion. + +Parameters: + +* **tuple1** – The first tuple to compare. +* **tuple2** – The second tuple to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertWarns(expected_warning, *args, **kwargs)` + +Fail unless a warning of class warnClass is triggered by the callable when invoked with specified positional and keyword arguments. If a different type of warning is triggered, it will not be handled: depending on the other warning filtering rules in effect, it might be silenced, printed out, or raised as an exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertWarns(SomeWarning): + do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertWarns is used as a context object. + +The context manager keeps a reference to the first matching warning as the ‘warning’ attribute; similarly, the ‘filename’ and ‘lineno’ attributes give you information about the line of Python code from which the warning was triggered. This allows you to inspect the warning after the assertion: + +``` +with self.assertWarns(SomeWarning) as cm: + do_something() +the_warning = cm.warning +self.assertEqual(the_warning.some_attribute, 147) +``` + +`assertWarnsRegex(expected_warning, expected_regex, *args, **kwargs)` + +Asserts that the message in a triggered warning matches a regexp. Basic functioning is similar to assertWarns() with the addition that only warnings whose messages also match the regular expression are considered successful matches. + +Parameters: + +* **expected_warning** – Warning class expected to be triggered. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertWarnsRegex is used as a context manager. + +`fail(msg=None)` + +Fail immediately, with the given message. + +`static get_abs_path(path)` + +Get absolute path relative to current directory. + +`get_absolute_machine_path()` + +Return absolute machine path. + +`get_config_file()` + +Return a string name of the machine config file to use for the tests in this class. + +You should override this method in your own test class to point to the config file you need for your tests. +Returns: A string name of the machine config file to use, complete with the .yaml file extension. + +For example: + +``` +def get_config_file(self): + return 'my_config.yaml' +``` + +`get_enable_plugins()` + +Control whether tests in this class should load MPF plugins. + +Returns: True or False + +The default is False. To load plugins in your test class, add the following: + +``` +def get_enable_plugins(self): + return True +` + +`get_machine_path()` + +Return a string name of the path to the machine folder to use for the tests in this class. + +You should override this method in your own test class to point to the machine folder root you need for your tests. +Returns: A string name of the machine path to use + +For example: + +``` +def get_machine_path(self): + return 'tests/machine_files/my_test/' +``` + +Note that this path is relative to the MPF package root + +`get_options()` + +Return options for the machine controller. + +`get_platform()` + +Force this test class to use a certain platform. +Returns: String name of the platform this test class will use. + +If you don’t include this method in your test class, the platform will be set to virtual. If you want to use the smart virtual platform, you would add the following to your test class: + +``` +def get_platform(self): + return 'smart_virtual` +``` + +`get_use_bcp() + +Control whether tests in this class should use BCP. + +Returns: True or False + +The default is False. To use BCP in your test class, add the following: + +``` +def get_use_bcp(self): + return True +``` + +`hit_and_release_switch(name)` + +Momentarily activates and then deactivates a switch. + +Parameters: + +* **name** – The name of the switch to hit. + +This method immediately activates and deactivates a switch with no time in between. + +`hit_and_release_switches_simultaneously(names)` + +Momentarily activates and then deactivates multiple switches. + +Switches are hit sequentially and then released sequentially. Events are only processed at the end of the sequence which is useful to reproduce race conditions when processing nearly simultaneous hits. + +Parameters: + +* **names** – The names of the switches to hit and release. + +`hit_switch_and_run(name, delta)` + +Activates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +Note that this method does not deactivate the switch once the time has been advanced, meaning the switch stays active. To make the switch inactive, use the release_switch_and_run(). + +`machine_run()` + +Process any delays, timers, or anything else scheduled. + +Note this is the same as: + +self.advance_time_and_run(0) + +`mock_event(event_name)` + +Configure an event to be mocked. + +Parameters: + +* **event_name** – String name of the event to mock. + +Mocking an event is an easy way to check if an event was called without configuring some kind of callback action in your tests. + +Note that an event must be mocked here before it’s posted in order for assertEventNotCalled() and assertEventCalled() to work. + +Mocking an event will not “break” it. In other words, any other registered handlers for this event will also be called even if the event has been mocked. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will be True +self.post_event('my_event') +self.assertEventCalled('my_event') # This will also be True +``` + +`post_event(event_name, run_time=0)` + +Post an MPF event and optionally advance the time. + +Parameters: + +* **event_name** – String name of the event to post +* **run_time** – How much time (in seconds) the test should advance after this event has been posted. + +For example, to post an event called “shot1_hit”: + +``` +self.post_event('shot1_hit') +``` + +To post an event called “tilt” and then advance the time 1.5 seconds: + +``` +self.post_event('tilt', 1.5) +``` + +`post_event_with_params(event_name, **params)` + +Post an MPF event with kwarg parameters. + +Parameters: + +* **event_name** – String name of the event to post +* ****params** – One or more kwarg key/value pairs to post with the event. + +For example, to post an event called “jackpot” with the parameters count=1 and first_time=True, you would use: + +``` +self.post_event('jackpot', count=1, first_time=True) +``` + +`post_relay_event_with_params(event_name, **params)` + +Post a relay event synchronously and return the result. + +`release_switch_and_run(name, delta)` + +Deactivates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +`reset_mock_events()` + +Reset all mocked events. + +This will reset the count of number of times called every mocked event is. + +`restore_sys_path()` + +Restore sys path after test. + +`save_and_prepare_sys_path()` + +Save sys path and prepare it for the test. + +`setUp()` + +Setup test. + +`set_num_balls_known(balls)` + +Set the ball controller’s num_balls_known attribute. + +This is needed for tests where you don’t have any ball devices and other situations where you need the ball controller to think the machine has a certain amount of balls to run a test. + +Example: + +self.set_num_balls_known(3) + +`shortDescription()` + +Returns a one-line description of the test, or None if no description has been provided. + +The default implementation of this method returns the first line of the specified test method’s docstring. + +`skipTest(reason)` + +Skip this test. + +`start_mode(mode)` + +Start mode. + +`stop_mode(mode)` + +Stop mode. + +`tearDown()` + +Tear down test. + +`static unittest_verbosity()` + +Return the verbosity setting of the currently running unittest program, or 0 if none is running. + +Returns: An integer value of the current verbosity setting. + + diff --git a/docs/code/api_reference/testing_class_api/MpfFakeGameTestCase.md b/docs/code/api_reference/testing_class_api/MpfFakeGameTestCase.md new file mode 100644 index 0000000000..52229f1d72 --- /dev/null +++ b/docs/code/api_reference/testing_class_api/MpfFakeGameTestCase.md @@ -0,0 +1,775 @@ + +# MpfFakeGameTestCase + +`class mpf.tests.MpfFakeGameTestCase.MpfFakeGameTestCase(methodName)` + +Bases: mpf.tests.MpfGameTestCase.MpfGameTestCase + +Test case for a game that does not require ball devices & start switches. + +Often times you need to write a test that is able to start a game. However in order to start a game, MPF requires lots of things, like having proper ball devices and a start button and stuff like that. + +This test overwrites the start_game() and drain_ball() methods of the MpfGameTestCase class so that you can start games and drain balls without actually having any ball devices configured. + +## Methods & Attributes + +The MpfFakeGameTestCase has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`add_player()` + +Add a player to the current game. + +This method hits and releases a switch called s_start and then verifies that the player count actually increased by 1. + +You can call this method multiple times to add multiple players. For example, to start a game and then add 2 additional players (for 3 players total), you would use: + +``` +self.start_game() +self.add_player() +self.add_player() +``` + +`static add_to_config_validator(machine, key, new_dict)` + +Add config dict to validator. + +`advance_time_and_run(delta=1.0)` + +Advance the test clock and run anything that should run during that time. +Parameters: delta – How much time to advance the test clock by (in seconds) + +This method will cause anything scheduled during the time to run, including things like delays, timers, etc. + +Advancing the clock will happen in multiple small steps if things are scheduled to happen during this advance. For example, you can advance the clock 10 seconds like this: + +self.advance_time_and_run(10) + +If there is a delay callback that is scheduled to happen in 2 seconds, then this method will advance the clock 2 seconds, process that delay, and then advance the remaining 8 seconds. + +`assertAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are unequal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is more than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +If the two objects compare equal then they will automatically compare almost equal. + +`assertAvailableBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is available on a playfield. + +`assertBallNumber(number)` + +Asserts that the current ball is a certain ball numebr. + +Parameters: + +* **number** – The number to check. + +Raises: Assertion error if there is no game in progress or if – the current ball is not the ball number passed. – + +The following code will check to make sure the game is on Ball 1: + +``` +self.assertBallNumber(1) +``` + +`assertBallsInPlay(balls)` + +Asserts that a certain number of balls are in play. + +Note that the number of balls in play is not necessarily the same as the number of balls on the playfield. (For example, a ball could be held in a ball device, or the machine could be in the process of adding a ball to the platfield.) +Parameters: balls – The number of balls you want to assert are in play. + +To assert that there are 3 balls in play (perhaps during a multiball), you would use: + +self.assertBallsInPlay(3) + +`assertBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is on a playfield. + +`assertColorAlmostEqual(color1, color2, delta=6)` + +Assert that two color are almost equal. + +Parameters: + +* **color1** – The first color, as an RGBColor instance or 3-item iterable. +* **color2** – The second color, as an RGBColor instance or 3-item iterable. +* **delta** – How close the colors have to be. The deltas between red, green, and blue are added together and must be less or equal to this value for this assertion to succeed. + +`assertCountEqual(first, second, msg=None)` + +An unordered sequence comparison asserting that the same elements, regardless of order. If the same element occurs more than once, it verifies that the elements occur the same number of times. + +self.assertEqual(Counter(list(first)), +Counter(list(second))) + +Example: +``` +[0, 1, 1] and [1, 0, 1] compare equal. +[0, 0, 1] and [0, 1] compare unequal. +``` +`assertDictContainsSubset(subset, dictionary, msg=None)` + +Checks whether dictionary is a superset of subset. + +`assertEqual(first, second, msg=None)` + +Fail if the two objects are unequal as determined by the ‘==’ operator. + +`assertEventCalled(event_name, times=None)` + +Assert that event was called. + +Parameters: + +* **event_name** – String name of the event to check. +* **times** – An optional value to confirm the number of times the event was called. Default of None means this method will pass as long as the event has been called at least once. + +If you want to reset the times count, you can mock the event again. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 1) # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 2) # This will pass +``` + +`assertEventCalledWith(event_name, **kwargs)` + +Assert an event was called with certain kwargs. + +Parameters: + +* **event_name** – String name of the event to check. +* ****kwargs** – Name/value parameters to check. + +For example: + +``` +self.mock_event('jackpot') + +self.post_event('jackpot', count=1, first_time=True) +self.assertEventCalled('jackpot') # This will pass +self.assertEventCalledWith('jackpot', count=1, first_time=True) # This will also pass +self.assertEventCalledWith('jackpot', count=1, first_time=False) # This will fail +``` + +`assertEventNotCalled(event_name)` + +Assert that event was not called. + +Parameters: + +* **event_name** – String name of the event to check. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +`assertFalse(expr, msg=None)` + +Check that the expression is false. + +`assertGameIsNotRunning()` + +Assert a game is not running. + +Example: + +``` +self.assertGameIsNotRunning() +``` + +`assertGameIsRunning()` + +Assert a game is running. + +Example: + +``` +self.assertGameIsRunning() +``` + +`assertGreater(a, b, msg=None)` + +Just like self.assertTrue(a > b), but with a nicer default message. + +`assertGreaterEqual(a, b, msg=None)` + +Just like self.assertTrue(a >= b), but with a nicer default message. + +`assertIn(member, container, msg=None)` + +Just like self.assertTrue(a in b), but with a nicer default message. + +`assertIs(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is b), but with a nicer default message. + +`assertIsInstance(obj, cls, msg=None)` + +Same as self.assertTrue(isinstance(obj, cls)), with a nicer default message. + +`assertIsNone(obj, msg=None)` + +Same as self.assertTrue(obj is None), with a nicer default message. + +`assertIsNot(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is not b), but with a nicer default message. + +`assertIsNotNone(obj, msg=None)` + +Included for symmetry with assertIsNone. + +`assertLess(a, b, msg=None)` + +Just like self.assertTrue(a < b), but with a nicer default message. + +`assertLessEqual(a, b, msg=None)` + +Just like self.assertTrue(a <= b), but with a nicer default message. + +`assertLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel has a certain brightness. + +`assertLightColor(light_name, color)` + +Assert that a light exists and shows one color. + +`assertLightColors(light_name, color_list, secs=1, check_delta=0.1)` + +Assert that a light exists and shows all colors in a list over a period. + +`assertLightFlashing(light_name, color=None, secs=1, check_delta=0.1)` + +Assert that a light exists and is flashing. + +`assertLightOff(light_name)` + +Assert that a light exists and is off. + +`assertLightOn(light_name)` + +Assert that a light exists and is on. + +`assertListEqual(list1, list2, msg=None)` + +A list-specific equality assertion. + +Parameters: + +* **list1** – The first list to compare. +* **list2** – The second list to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertLogs(logger=None, level=None) + +Fail unless a log message of level level or higher is emitted on logger_name or its children. If omitted, level defaults to INFO and logger defaults to the root logger. + +This method must be used as a context manager, and will yield a recording object with two attributes: output and records. At the end of the context manager, the output attribute will be a list of the matching formatted log messages and the records attribute will be a list of the corresponding LogRecord objects. + +Example: + +``` +with self.assertLogs('foo', level='INFO') as cm: +logging.getLogger('foo').info('first message') +logging.getLogger('foo.bar').error('second message') +self.assertEqual(cm.output, ['INFO:foo:first message', + 'ERROR:foo.bar:second message']) +``` + +`assertMachineVarEqual(value, machine_var)` + +Assert that a machine variable exists and has a certain value. + +`assertModeNotRunning(mode_name)` + +Assert that a mode exists and is not running. + +`assertModeRunning(mode_name)` + +Assert that a mode exists and is running. + +`assertMultiLineEqual(first, second, msg=None)` + +Assert that two multi-line strings are equal. + +`assertNotAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are equal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is less than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +Objects that are equal automatically fail. + +`assertNotEqual(first, second, msg=None)` + +Fail if the two objects are equal as determined by the ‘!=’ operator. + +`assertNotIn(member, container, msg=None)` + +Just like self.assertTrue(a not in b), but with a nicer default message. + +`assertNotIsInstance(obj, cls, msg=None)` + +Included for symmetry with assertIsInstance. + +`assertNotLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel does not have a certain brightness. + +`assertNotLightColor(light_name, color)` + +Assert that a light exists and does not show a certain color. + +`assertNotRegex(text, unexpected_regex, msg=None) + +Fail the test if the text matches the regular expression. + +`assertNumBallsKnown(balls)` + +Assert that a certain number of balls are known in the machine. + +`assertPlaceholderEvaluates(expected, condition)` + +Assert that a placeholder evaluates to a certain value. + +`assertPlayerCount(count)` + +Asserts that count players exist. + +Parameters: + +* **count** – The expected number of players. + +For example, to assert that the to players are in the game: + +``` +self.assertPlayerCount(2) +``` + +`assertPlayerNumber(number)` + +Asserts that the current player is a certain player number. +Parameters: number – The player number you can to assert is the current player. + +For example, to assert that the current player is Player 2, you would use: + +self.assertPlayerNumber(2) + +`assertPlayerVarEqual(value, player_var)` + +Assert that a player variable exists and has a certain value. + +`assertRaises(expected_exception, *args, **kwargs)` + +Fail unless an exception of class expected_exception is raised by the callable when invoked with specified positional and keyword arguments. If a different type of exception is raised, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertRaises(SomeException): +do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertRaises is used as a context object. + +The context manager keeps a reference to the exception as the ‘exception’ attribute. This allows you to inspect the exception after the assertion: + +``` +with self.assertRaises(SomeException) as cm: +do_something() +the_exception = cm.exception +self.assertEqual(the_exception.error_code, 3) +``` + +`assertRaisesRegex(expected_exception, expected_regex, *args, **kwargs)` + +Asserts that the message in a raised exception matches a regex. + +Parameters: + +* **expected_exception** – Exception class expected to be raised. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertRaisesRegex is used as a context manager. + +`assertRegex(text, expected_regex, msg=None)` + +Fail the test unless the text matches the regular expression. + +`assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)` + +An equality assertion for ordered sequences (like lists and tuples). + +For the purposes of this function, a valid ordered sequence type is one which can be indexed, has a length, and has an equality operator. + +Parameters: + +* **seq1** – The first sequence to compare. +* **seq2** – The second sequence to compare. +* **seq_type** – The expected datatype of the sequences, or None if no datatype should be enforced. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertSetEqual(set1, set2, msg=None)` + +A set-specific equality assertion. + +Parameters: + +* **set1** – The first set to compare. +* **set2** – The second set to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +assertSetEqual uses ducktyping to support different types of sets, and is optimized for sets specifically (parameters must support a difference method). + +`assertSwitchState(name, state)` + +Assert that a switch exists and has a certain state. + +`assertTrue(expr, msg=None)` + +Check that the expression is true. + +`assertTupleEqual(tuple1, tuple2, msg=None)` + +A tuple-specific equality assertion. + +Parameters: + +* **tuple1** – The first tuple to compare. +* **tuple2** – The second tuple to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertWarns(expected_warning, *args, **kwargs)` + +Fail unless a warning of class warnClass is triggered by the callable when invoked with specified positional and keyword arguments. If a different type of warning is triggered, it will not be handled: depending on the other warning filtering rules in effect, it might be silenced, printed out, or raised as an exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertWarns(SomeWarning): +do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertWarns is used as a context object. + +The context manager keeps a reference to the first matching warning as the ‘warning’ attribute; similarly, the ‘filename’ and ‘lineno’ attributes give you information about the line of Python code from which the warning was triggered. This allows you to inspect the warning after the assertion: + +``` +with self.assertWarns(SomeWarning) as cm: +do_something() +the_warning = cm.warning +self.assertEqual(the_warning.some_attribute, 147) +``` + +`assertWarnsRegex(expected_warning, expected_regex, *args, **kwargs)` + +Asserts that the message in a triggered warning matches a regexp. Basic functioning is similar to assertWarns() with the addition that only warnings whose messages also match the regular expression are considered successful matches. + +Parameters: + +* **expected_warning** – Warning class expected to be triggered. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertWarnsRegex is used as a context manager. + +`drain_all_balls()` + +Drain all the balls in play. + +Does not actually require any ball devices to be present in the config file. + +`drain_one_ball()` + +Drain one ball. + +Does not actually require any ball devices to be present in the config file. + +`fail(msg=None)` + +Fail immediately, with the given message. + +`fill_troughs()` + +Fill all ball devices tagged with trough with balls. + +`static get_abs_path(path)` + +Get absolute path relative to current directory. + +`get_absolute_machine_path()` + +Return absolute machine path. + +`get_config_file()` + +Return a string name of the machine config file to use for the tests in this class. + +You should override this method in your own test class to point to the config file you need for your tests. +Returns: A string name of the machine config file to use, complete with the .yaml file extension. + +For example: + +``` +def get_config_file(self): +return 'my_config.yaml' +``` + +`get_enable_plugins()` + +Control whether tests in this class should load MPF plugins. + +Returns: True or False + +The default is False. To load plugins in your test class, add the following: + +``` +def get_enable_plugins(self): +return True +``` + +`get_machine_path()` + +Return a string name of the path to the machine folder to use for the tests in this class. + +You should override this method in your own test class to point to the machine folder root you need for your tests. +Returns: A string name of the machine path to use + +For example: + +``` +def get_machine_path(self): +return 'tests/machine_files/my_test/' +``` + +Note that this path is relative to the MPF package root + +`get_options()` + +Return options for the machine controller. + +`get_platform()` + +Force this test class to use a certain platform. +Returns: String name of the platform this test class will use. + +If you don’t include this method in your test class, the platform will be set to virtual. If you want to use the smart virtual platform, you would add the following to your test class: + +``` +def get_platform(self): +return 'smart_virtual` +``` + +`get_use_bcp()` + +Control whether tests in this class should use BCP. + +Returns: True or False + +The default is False. To use BCP in your test class, add the following: + +``` +def get_use_bcp(self): +return True +``` + +`hit_and_release_switch(name)` + +Momentarily activates and then deactivates a switch. + +Parameters: + +* **name** – The name of the switch to hit. + +This method immediately activates and deactivates a switch with no time in between. + +`hit_and_release_switches_simultaneously(names)` + +Momentarily activates and then deactivates multiple switches. + +Switches are hit sequentially and then released sequentially. Events are only processed at the end of the sequence which is useful to reproduce race conditions when processing nearly simultaneous hits. + +Parameters: + +* **names** – The names of the switches to hit and release. + +`hit_switch_and_run(name, delta)` + +Activates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +Note that this method does not deactivate the switch once the time has been advanced, meaning the switch stays active. To make the switch inactive, use the release_switch_and_run(). + +`machine_run()` + +Process any delays, timers, or anything else scheduled. + +Note this is the same as: + +self.advance_time_and_run(0) + +`mock_event(event_name)` + +Configure an event to be mocked. +Parameters: event_name – String name of the event to mock. + +Mocking an event is an easy way to check if an event was called without configuring some kind of callback action in your tests. + +Note that an event must be mocked here before it’s posted in order for assertEventNotCalled() and assertEventCalled() to work. + +Mocking an event will not “break” it. In other words, any other registered handlers for this event will also be called even if the event has been mocked. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will be True +self.post_event('my_event') +self.assertEventCalled('my_event') # This will also be True +``` + +`post_event(event_name, run_time=0)` + +Post an MPF event and optionally advance the time. + +Parameters: + +* **event_name** – String name of the event to post +* **run_time** – How much time (in seconds) the test should advance after this event has been posted. + +For example, to post an event called “shot1_hit”: + +self.post_event('shot1_hit') + +To post an event called “tilt” and then advance the time 1.5 seconds: + +self.post_event('tilt', 1.5) + +`post_event_with_params(event_name, **params)` + +Post an MPF event with kwarg parameters. + +Parameters: + +* **event_name** – String name of the event to post +* ****params** – One or more kwarg key/value pairs to post with the event. + +For example, to post an event called “jackpot” with the parameters count=1 and first_time=True, you would use: + +``` +self.post_event('jackpot', count=1, first_time=True) +``` + +`post_relay_event_with_params(event_name, **params)` + +Post a relay event synchronously and return the result. + +`release_switch_and_run(name, delta)` + +Deactivates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +`reset_mock_events()` + +Reset all mocked events. + +This will reset the count of number of times called every mocked event is. + +`restore_sys_path()` + +Restore sys path after test. + +`save_and_prepare_sys_path()` + +Save sys path and prepare it for the test. + +`setUp()` + +Setup test. + +`set_num_balls_known(balls)` + +Set the ball controller’s num_balls_known attribute. + +This is needed for tests where you don’t have any ball devices and other situations where you need the ball controller to think the machine has a certain amount of balls to run a test. + +Example: + +``` +self.set_num_balls_known(3) +``` + +`shortDescription()` + +Returns a one-line description of the test, or None if no description has been provided. + +The default implementation of this method returns the first line of the specified test method’s docstring. + +`skipTest(reason)` + +Skip this test. + +`start_game(num_balls_known=3)` + +Start a game. + +Does not require ball devices or a start button to be present in the config file. Sets the number of known balls to 3. + +`start_mode(mode)` + +Start mode. + +`start_two_player_game()` + +Start two player game. + +`stop_game(stop_time=1)` + +Stop the current game. + +This method asserts that a game is running, then call’s the game mode’s end_game() method, then asserts that the game has successfully stopped. + +Example: + +``` +self.stop_game() +``` + +`stop_mode(mode)` + +Stop mode. + +`tearDown()` + +Tear down test. + +`static unittest_verbosity()` + +Return the verbosity setting of the currently running unittest program, or 0 if none is running. + +Returns: An integer value of the current verbosity setting. + diff --git a/docs/code/api_reference/testing_class_api/MpfGameTestCase.md b/docs/code/api_reference/testing_class_api/MpfGameTestCase.md new file mode 100644 index 0000000000..f361d493f8 --- /dev/null +++ b/docs/code/api_reference/testing_class_api/MpfGameTestCase.md @@ -0,0 +1,780 @@ + +# MpfGameTestCase + +`class mpf.tests.MpfGameTestCase.MpfGameTestCase(methodName)` + +Bases: mpf.tests.MpfTestCase.MpfTestCase + +Test case for starting and running games. + +This is based on MpfTestCase but adds methods and assertions related to running games (rather than just testing MPF components or devices). + +## Methods & Attributes + +The MpfGameTestCase has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`add_player()` + +Add a player to the current game. + +This method hits and releases a switch called s_start and then verifies that the player count actually increased by 1. + +You can call this method multiple times to add multiple players. For example, to start a game and then add 2 additional players (for 3 players total), you would use: + +``` +self.start_game() +self.add_player() +self.add_player() +``` + +`static add_to_config_validator(machine, key, new_dict)` + +Add config dict to validator. + +`advance_time_and_run(delta=1.0)` + +Advance the test clock and run anything that should run during that time. + +Parameters: + +* **delta** – How much time to advance the test clock by (in seconds) + +This method will cause anything scheduled during the time to run, including things like delays, timers, etc. + +Advancing the clock will happen in multiple small steps if things are scheduled to happen during this advance. For example, you can advance the clock 10 seconds like this: + +self.advance_time_and_run(10) + +If there is a delay callback that is scheduled to happen in 2 seconds, then this method will advance the clock 2 seconds, process that delay, and then advance the remaining 8 seconds. + +`assertAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are unequal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is more than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +If the two objects compare equal then they will automatically compare almost equal. + +`assertAvailableBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is available on a playfield. + +`assertBallNumber(number)` + +Asserts that the current ball is a certain ball numebr. +Parameters: + +* **number** – The number to check. + +Raises: + +Assertion error if there is no game in progress or if – +the current ball is not the ball number passed. – + +The following code will check to make sure the game is on Ball 1: + +self.assertBallNumber(1) + +`assertBallsInPlay(balls)` + +Asserts that a certain number of balls are in play. + +Note that the number of balls in play is not necessarily the same as the number of balls on the playfield. (For example, a ball could be held in a ball device, or the machine could be in the process of adding a ball to the platfield.) + +Parameters: + +* **balls** – The number of balls you want to assert are in play. + +To assert that there are 3 balls in play (perhaps during a multiball), you would use: + +self.assertBallsInPlay(3) + +`assertBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is on a playfield. + +`assertColorAlmostEqual(color1, color2, delta=6)` + +Assert that two color are almost equal. + +Parameters: + +* **color1** – The first color, as an RGBColor instance or 3-item iterable. +* **color2** – The second color, as an RGBColor instance or 3-item iterable. +* **delta** – How close the colors have to be. The deltas between red, green, and blue are added together and must be less or equal to this value for this assertion to succeed. + +`assertCountEqual(first, second, msg=None)` + +An unordered sequence comparison asserting that the same elements, regardless of order. If the same element occurs more than once, it verifies that the elements occur the same number of times. + +self.assertEqual(Counter(list(first)), +Counter(list(second))) + +Example: + +``` +[0, 1, 1] and [1, 0, 1] compare equal. +[0, 0, 1] and [0, 1] compare unequal. +``` + +`assertDictContainsSubset(subset, dictionary, msg=None)` + +Checks whether dictionary is a superset of subset. + +`assertEqual(first, second, msg=None)` + +Fail if the two objects are unequal as determined by the ‘==’ operator. + +`assertEventCalled(event_name, times=None)` + +Assert that event was called. + +Parameters: + +* **event_name** – String name of the event to check. +* **times** – An optional value to confirm the number of times the event was called. Default of None means this method will pass as long as the event has been called at least once. + +If you want to reset the times count, you can mock the event again. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 1) # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 2) # This will pass +``` + +`assertEventCalledWith(event_name, **kwargs)` + +Assert an event was called with certain kwargs. + +Parameters: + +* **event_name** – String name of the event to check. +* ****kwargs** – Name/value parameters to check. + +For example: + +``` +self.mock_event('jackpot') + +self.post_event('jackpot', count=1, first_time=True) +self.assertEventCalled('jackpot') # This will pass +self.assertEventCalledWith('jackpot', count=1, first_time=True) # This will also pass +self.assertEventCalledWith('jackpot', count=1, first_time=False) # This will fail +``` + +`assertEventNotCalled(event_name)` + +Assert that event was not called. + +Parameters: + +* **event_name** – String name of the event to check. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +`assertFalse(expr, msg=None)` + +Check that the expression is false. + +`assertGameIsNotRunning()` + +Assert a game is not running. + +Example: + +``` +self.assertGameIsNotRunning() +``` + +`assertGameIsRunning()` + +Assert a game is running. + +Example: + +``` +self.assertGameIsRunning() +``` + +`assertGreater(a, b, msg=None)` + +Just like self.assertTrue(a > b), but with a nicer default message. + +`assertGreaterEqual(a, b, msg=None)` + +Just like self.assertTrue(a >= b), but with a nicer default message. + +`assertIn(member, container, msg=None)` + +Just like self.assertTrue(a in b), but with a nicer default message. + +`assertIs(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is b), but with a nicer default message. + +`assertIsInstance(obj, cls, msg=None)` + +Same as self.assertTrue(isinstance(obj, cls)), with a nicer default message. + +`assertIsNone(obj, msg=None)` + +Same as self.assertTrue(obj is None), with a nicer default message. + +`assertIsNot(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is not b), but with a nicer default message. + +`assertIsNotNone(obj, msg=None)` + +Included for symmetry with assertIsNone. + +`assertLess(a, b, msg=None)` + +Just like self.assertTrue(a < b), but with a nicer default message. + +`assertLessEqual(a, b, msg=None)` + +Just like self.assertTrue(a <= b), but with a nicer default message. + +`assertLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel has a certain brightness. + +`assertLightColor(light_name, color)` + +Assert that a light exists and shows one color. + +`assertLightColors(light_name, color_list, secs=1, check_delta=0.1)` + +Assert that a light exists and shows all colors in a list over a period. + +`assertLightFlashing(light_name, color=None, secs=1, check_delta=0.1)` + +Assert that a light exists and is flashing. + +`assertLightOff(light_name)` + +Assert that a light exists and is off. + +`assertLightOn(light_name)` + +Assert that a light exists and is on. + +`assertListEqual(list1, list2, msg=None)` + +A list-specific equality assertion. + +Parameters: + +* **list1** – The first list to compare. +* **list2** – The second list to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertLogs(logger=None, level=None)` + +Fail unless a log message of level level or higher is emitted on logger_name or its children. If omitted, level defaults to INFO and logger defaults to the root logger. + +This method must be used as a context manager, and will yield a recording object with two attributes: output and records. At the end of the context manager, the output attribute will be a list of the matching formatted log messages and the records attribute will be a list of the corresponding LogRecord objects. + +Example: + +``` +with self.assertLogs('foo', level='INFO') as cm: +logging.getLogger('foo').info('first message') +logging.getLogger('foo.bar').error('second message') +self.assertEqual(cm.output, ['INFO:foo:first message', +'ERROR:foo.bar:second message']) +``` + +`assertMachineVarEqual(value, machine_var)` + +Assert that a machine variable exists and has a certain value. + +`assertModeNotRunning(mode_name)` + +Assert that a mode exists and is not running. + +`assertModeRunning(mode_name)` + +Assert that a mode exists and is running. + +`assertMultiLineEqual(first, second, msg=None)` + +Assert that two multi-line strings are equal. + +`assertNotAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are equal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is less than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +Objects that are equal automatically fail. + +`assertNotEqual(first, second, msg=None)` + +Fail if the two objects are equal as determined by the ‘!=’ operator. + +`assertNotIn(member, container, msg=None)` + +Just like self.assertTrue(a not in b), but with a nicer default message. + +`assertNotIsInstance(obj, cls, msg=None)` + +Included for symmetry with assertIsInstance. + +`assertNotLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel does not have a certain brightness. + +`assertNotLightColor(light_name, color)` + +Assert that a light exists and does not show a certain color. + +`assertNotRegex(text, unexpected_regex, msg=None)` + +Fail the test if the text matches the regular expression. + +`assertNumBallsKnown(balls)` + +Assert that a certain number of balls are known in the machine. + +`assertPlaceholderEvaluates(expected, condition)` + +Assert that a placeholder evaluates to a certain value. + +`assertPlayerCount(count)` + +Asserts that count players exist. + +Parameters: + +* **count** – The expected number of players. + +For example, to assert that the to players are in the game: + +self.assertPlayerCount(2) + +`assertPlayerNumber(number)` + +Asserts that the current player is a certain player number. + +Parameters: + +* **number** – The player number you can to assert is the current player. + +For example, to assert that the current player is Player 2, you would use: + +self.assertPlayerNumber(2) + +`assertPlayerVarEqual(value, player_var)` + +Assert that a player variable exists and has a certain value. + +`assertRaises(expected_exception, *args, **kwargs)` + +Fail unless an exception of class expected_exception is raised by the callable when invoked with specified positional and keyword arguments. If a different type of exception is raised, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertRaises(SomeException): +do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertRaises is used as a context object. + +The context manager keeps a reference to the exception as the ‘exception’ attribute. This allows you to inspect the exception after the assertion: + +``` +with self.assertRaises(SomeException) as cm: +do_something() +the_exception = cm.exception +self.assertEqual(the_exception.error_code, 3) +``` + +`assertRaisesRegex(expected_exception, expected_regex, *args, **kwargs)` + +Asserts that the message in a raised exception matches a regex. + +Parameters: + +* **expected_exception** – Exception class expected to be raised. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertRaisesRegex is used as a context manager. + +`assertRegex(text, expected_regex, msg=None)` + +Fail the test unless the text matches the regular expression. + +`assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)` + +An equality assertion for ordered sequences (like lists and tuples). + +For the purposes of this function, a valid ordered sequence type is one which can be indexed, has a length, and has an equality operator. + +Parameters: + +* **seq1** – The first sequence to compare. +* **seq2** – The second sequence to compare. +* **seq_type** – The expected datatype of the sequences, or None if no datatype should be enforced. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertSetEqual(set1, set2, msg=None)` + +A set-specific equality assertion. + +Parameters: + +* **set1** – The first set to compare. +* **set2** – The second set to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +assertSetEqual uses ducktyping to support different types of sets, and is optimized for sets specifically (parameters must support a difference method). + +`assertSwitchState(name, state)` + +Assert that a switch exists and has a certain state. + +`assertTrue(expr, msg=None)` + +Check that the expression is true. + +`assertTupleEqual(tuple1, tuple2, msg=None)` + +A tuple-specific equality assertion. + +Parameters: + +* **tuple1** – The first tuple to compare. +* **tuple2** – The second tuple to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertWarns(expected_warning, *args, **kwargs)` + +Fail unless a warning of class warnClass is triggered by the callable when invoked with specified positional and keyword arguments. If a different type of warning is triggered, it will not be handled: depending on the other warning filtering rules in effect, it might be silenced, printed out, or raised as an exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertWarns(SomeWarning): +do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertWarns is used as a context object. + +The context manager keeps a reference to the first matching warning as the ‘warning’ attribute; similarly, the ‘filename’ and ‘lineno’ attributes give you information about the line of Python code from which the warning was triggered. This allows you to inspect the warning after the assertion: + +``` +with self.assertWarns(SomeWarning) as cm: +do_something() +the_warning = cm.warning +self.assertEqual(the_warning.some_attribute, 147) +``` + +`assertWarnsRegex(expected_warning, expected_regex, *args, **kwargs)` + +Asserts that the message in a triggered warning matches a regexp. Basic functioning is similar to assertWarns() with the addition that only warnings whose messages also match the regular expression are considered successful matches. + +Parameters: + +* **expected_warning** – Warning class expected to be triggered. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertWarnsRegex is used as a context manager. + +`drain_all_balls()` + +Drain all balls in play. + +`drain_one_ball()` + +Drain a single ball. + +If more than 1 ball is in play, this method will need to be called once for each ball in order to end the current ball. + +If you want to drain all balls use drain_all_balls. + +`fail(msg=None)` + +Fail immediately, with the given message. + +`fill_troughs()` + +Fill all ball devices tagged with trough with balls. + +`static get_abs_path(path)` + +Get absolute path relative to current directory. + +`get_absolute_machine_path()` + +Return absolute machine path. + +`get_config_file()` + +Return a string name of the machine config file to use for the tests in this class. + +You should override this method in your own test class to point to the config file you need for your tests. +Returns: A string name of the machine config file to use, complete with the .yaml file extension. + +For example: + +``` +def get_config_file(self): +return 'my_config.yaml' +``` + +`get_enable_plugins()` + +Control whether tests in this class should load MPF plugins. + +Returns: True or False + +The default is False. To load plugins in your test class, add the following: + +def get_enable_plugins(self): +return True + +`get_machine_path()` + +Return a string name of the path to the machine folder to use for the tests in this class. + +You should override this method in your own test class to point to the machine folder root you need for your tests. +Returns: A string name of the machine path to use + +For example: + +``` +def get_machine_path(self): +return 'tests/machine_files/my_test/' +``` + +Note that this path is relative to the MPF package root + +`get_options()` + +Return options for the machine controller. + +`get_platform()` + +Force this test class to use a certain platform. +Returns: String name of the platform this test class will use. + +If you don’t include this method in your test class, the platform will be set to virtual. If you want to use the smart virtual platform, you would add the following to your test class: + +def get_platform(self): +return 'smart_virtual` + +`get_use_bcp()` + +Control whether tests in this class should use BCP. + +Returns: True or False + +The default is False. To use BCP in your test class, add the following: + +def get_use_bcp(self): +return True + +`hit_and_release_switch(name)` + +Momentarily activates and then deactivates a switch. + +Parameters: + +* **name** – The name of the switch to hit. + +This method immediately activates and deactivates a switch with no time in between. + +`hit_and_release_switches_simultaneously(names)` + +Momentarily activates and then deactivates multiple switches. + +Switches are hit sequentially and then released sequentially. Events are only processed at the end of the sequence which is useful to reproduce race conditions when processing nearly simultaneous hits. + +Parameters: + +* **names** – The names of the switches to hit and release. + +`hit_switch_and_run(name, delta)` + +Activates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +Note that this method does not deactivate the switch once the time has been advanced, meaning the switch stays active. To make the switch inactive, use the release_switch_and_run(). + +`machine_run()` + +Process any delays, timers, or anything else scheduled. + +Note this is the same as: + +self.advance_time_and_run(0) + +`mock_event(event_name)` + +Configure an event to be mocked. +Parameters: event_name – String name of the event to mock. + +Mocking an event is an easy way to check if an event was called without configuring some kind of callback action in your tests. + +Note that an event must be mocked here before it’s posted in order for assertEventNotCalled() and assertEventCalled() to work. + +Mocking an event will not “break” it. In other words, any other registered handlers for this event will also be called even if the event has been mocked. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will be True +self.post_event('my_event') +self.assertEventCalled('my_event') # This will also be True +``` + +`post_event(event_name, run_time=0)` + +Post an MPF event and optionally advance the time. + +Parameters: + +* **event_name** – String name of the event to post +* **run_time** – How much time (in seconds) the test should advance after this event has been posted. + +For example, to post an event called “shot1_hit”: + +self.post_event('shot1_hit') + +To post an event called “tilt” and then advance the time 1.5 seconds: + +self.post_event('tilt', 1.5) + +`post_event_with_params(event_name, **params)` + +Post an MPF event with kwarg parameters. + +Parameters: + +* **event_name** – String name of the event to post +* ****params** – One or more kwarg key/value pairs to post with the event. + +For example, to post an event called “jackpot” with the parameters count=1 and first_time=True, you would use: + +self.post_event('jackpot', count=1, first_time=True) + +`post_relay_event_with_params(event_name, **params)` + +Post a relay event synchronously and return the result. + +`release_switch_and_run(name, delta)` + +Deactivates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +`reset_mock_events()` + +Reset all mocked events. + +This will reset the count of number of times called every mocked event is. + +`restore_sys_path()` + +Restore sys path after test. + +`save_and_prepare_sys_path()` + +Save sys path and prepare it for the test. + +`setUp()` + +Setup test. + +`set_num_balls_known(balls)` + +Set the ball controller’s num_balls_known attribute. + +This is needed for tests where you don’t have any ball devices and other situations where you need the ball controller to think the machine has a certain amount of balls to run a test. + +Example: + +``` +self.set_num_balls_known(3) +``` + +`shortDescription()` + +Returns a one-line description of the test, or None if no description has been provided. + +The default implementation of this method returns the first line of the specified test method’s docstring. + +`skipTest(reason)` + +Skip this test. + +`start_game(num_balls_known=None)` + +Start a game. + +This method checks to make sure a game is not running, then hits and releases the s_start switch, and finally checks to make sure a game actually started properly. + +For example: + +``` +self.start_game() +``` + +`start_mode(mode)` + +Start mode. + +`start_two_player_game()` + +Start two player game. + +`stop_game(stop_time=1)` + +Stop the current game. + +This method asserts that a game is running, then call’s the game mode’s end_game() method, then asserts that the game has successfully stopped. + +Example: + +``` +self.stop_game() +``` + +`stop_mode(mode)` + +Stop mode. + +`tearDown()` + +Tear down test. + +`static unittest_verbosity()` + +Return the verbosity setting of the currently running unittest program, or 0 if none is running. + +Returns: An integer value of the current verbosity setting. + diff --git a/docs/code/api_reference/testing_class_api/MpfMachineTestCase.md b/docs/code/api_reference/testing_class_api/MpfMachineTestCase.md new file mode 100644 index 0000000000..3589c7458e --- /dev/null +++ b/docs/code/api_reference/testing_class_api/MpfMachineTestCase.md @@ -0,0 +1,652 @@ + +# MpfMachineTestCase + +`class mpf.tests.MpfMachineTestCase.MpfMachineTestCase(methodName='runTest')` + +Bases: mpf.tests.MpfMachineTestCase.BaseMpfMachineTestCase + +MPF only machine test case. + +## Methods & Attributes + +The MpfMachineTestCase has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static add_to_config_validator(machine, key, new_dict)` + +Add config dict to validator. + +`advance_time_and_run(delta=1.0)` + +Advance the test clock and run anything that should run during that time. +Parameters: delta – How much time to advance the test clock by (in seconds) + +This method will cause anything scheduled during the time to run, including things like delays, timers, etc. + +Advancing the clock will happen in multiple small steps if things are scheduled to happen during this advance. For example, you can advance the clock 10 seconds like this: + +self.advance_time_and_run(10) + +If there is a delay callback that is scheduled to happen in 2 seconds, then this method will advance the clock 2 seconds, process that delay, and then advance the remaining 8 seconds. + +`assertAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are unequal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is more than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +If the two objects compare equal then they will automatically compare almost equal. + +`assertAvailableBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is available on a playfield. + +`assertBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is on a playfield. + +`assertColorAlmostEqual(color1, color2, delta=6)` + +Assert that two color are almost equal. + +Parameters: + +* **color1** – The first color, as an RGBColor instance or 3-item iterable. +* **color2** – The second color, as an RGBColor instance or 3-item iterable. +* **delta** – How close the colors have to be. The deltas between red, green, and blue are added together and must be less or equal to this value for this assertion to succeed. + +`assertCountEqual(first, second, msg=None)` + +An unordered sequence comparison asserting that the same elements, regardless of order. If the same element occurs more than once, it verifies that the elements occur the same number of times. + +``` +self.assertEqual(Counter(list(first)), +Counter(list(second))) +``` + +Example: + +``` +[0, 1, 1] and [1, 0, 1] compare equal. +[0, 0, 1] and [0, 1] compare unequal. +``` + +`assertDictContainsSubset(subset, dictionary, msg=None)` + +Checks whether dictionary is a superset of subset. + +`assertEqual(first, second, msg=None)` + +Fail if the two objects are unequal as determined by the ‘==’ operator. + +`assertEventCalled(event_name, times=None)` + +Assert that event was called. + +Parameters: + +* **event_name** – String name of the event to check. +* **times** – An optional value to confirm the number of times the event was called. Default of None means this method will pass as long as the event has been called at least once. + +If you want to reset the times count, you can mock the event again. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 1) # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 2) # This will pass +``` + +`assertEventCalledWith(event_name, **kwargs)` + +Assert an event was called with certain kwargs. + +Parameters: + +* **event_name** – String name of the event to check. +* ****kwargs** – Name/value parameters to check. + +For example: + +``` +self.mock_event('jackpot') + +self.post_event('jackpot', count=1, first_time=True) +self.assertEventCalled('jackpot') # This will pass +self.assertEventCalledWith('jackpot', count=1, first_time=True) # This will also pass +self.assertEventCalledWith('jackpot', count=1, first_time=False) # This will fail +``` + +`assertEventNotCalled(event_name)` + +Assert that event was not called. + +Parameters: + +* **event_name** – String name of the event to check. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +`assertFalse(expr, msg=None)` + +Check that the expression is false. + +`assertGreater(a, b, msg=None)` + +Just like self.assertTrue(a > b), but with a nicer default message. + +`assertGreaterEqual(a, b, msg=None)` + +Just like self.assertTrue(a >= b), but with a nicer default message. + +`assertIn(member, container, msg=None)` + +Just like self.assertTrue(a in b), but with a nicer default message. + +`assertIs(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is b), but with a nicer default message. + +`assertIsInstance(obj, cls, msg=None)` + +Same as self.assertTrue(isinstance(obj, cls)), with a nicer default message. + +`assertIsNone(obj, msg=None)` + +Same as self.assertTrue(obj is None), with a nicer default message. + +`assertIsNot(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is not b), but with a nicer default message. + +`assertIsNotNone(obj, msg=None)` + +Included for symmetry with assertIsNone. + +`assertLess(a, b, msg=None)` + +Just like self.assertTrue(a < b), but with a nicer default message. + +`assertLessEqual(a, b, msg=None)` + +Just like self.assertTrue(a <= b), but with a nicer default message. + +`assertLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel has a certain brightness. + +`assertLightColor(light_name, color)` + +Assert that a light exists and shows one color. + +`assertLightColors(light_name, color_list, secs=1, check_delta=0.1)` + +Assert that a light exists and shows all colors in a list over a period. + +`assertLightFlashing(light_name, color=None, secs=1, check_delta=0.1)` + +Assert that a light exists and is flashing. + +`assertLightOff(light_name)` + +Assert that a light exists and is off. + +`assertLightOn(light_name)` + +Assert that a light exists and is on. + +`assertListEqual(list1, list2, msg=None)` + +A list-specific equality assertion. + +Parameters: + +* **list1** – The first list to compare. +* **list2** – The second list to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertLogs(logger=None, level=None)` + +Fail unless a log message of level level or higher is emitted on logger_name or its children. If omitted, level defaults to INFO and logger defaults to the root logger. + +This method must be used as a context manager, and will yield a recording object with two attributes: output and records. At the end of the context manager, the output attribute will be a list of the matching formatted log messages and the records attribute will be a list of the corresponding LogRecord objects. + +Example: + +``` +with self.assertLogs('foo', level='INFO') as cm: +logging.getLogger('foo').info('first message') +logging.getLogger('foo.bar').error('second message') +self.assertEqual(cm.output, ['INFO:foo:first message', +'ERROR:foo.bar:second message']) +``` + +`assertMachineVarEqual(value, machine_var)` + +Assert that a machine variable exists and has a certain value. + +`assertModeNotRunning(mode_name)` + +Assert that a mode exists and is not running. + +`assertModeRunning(mode_name)` + +Assert that a mode exists and is running. + +`assertMultiLineEqual(first, second, msg=None)` + +Assert that two multi-line strings are equal. + +`assertNotAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are equal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is less than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +Objects that are equal automatically fail. + +`assertNotEqual(first, second, msg=None)` + +Fail if the two objects are equal as determined by the ‘!=’ operator. + +`assertNotIn(member, container, msg=None)` + +Just like self.assertTrue(a not in b), but with a nicer default message. + +`assertNotIsInstance(obj, cls, msg=None)` + +Included for symmetry with assertIsInstance. + +`assertNotLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel does not have a certain brightness. + +`assertNotLightColor(light_name, color)` + +Assert that a light exists and does not show a certain color. + +`assertNotRegex(text, unexpected_regex, msg=None)` + +Fail the test if the text matches the regular expression. + +`assertNumBallsKnown(balls)` + +Assert that a certain number of balls are known in the machine. + +`assertPlaceholderEvaluates(expected, condition)` + +Assert that a placeholder evaluates to a certain value. + +`assertPlayerVarEqual(value, player_var)` + +Assert that a player variable exists and has a certain value. + +`assertRaises(expected_exception, *args, **kwargs)` + +Fail unless an exception of class expected_exception is raised by the callable when invoked with specified positional and keyword arguments. If a different type of exception is raised, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertRaises(SomeException): + do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertRaises is used as a context object. + +The context manager keeps a reference to the exception as the ‘exception’ attribute. This allows you to inspect the exception after the assertion: + +``` +with self.assertRaises(SomeException) as cm: + do_something() +the_exception = cm.exception +self.assertEqual(the_exception.error_code, 3) +``` + +`assertRaisesRegex(expected_exception, expected_regex, *args, **kwargs)` + +Asserts that the message in a raised exception matches a regex. + +Parameters: + +* **expected_exception** – Exception class expected to be raised. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertRaisesRegex is used as a context manager. + +`assertRegex(text, expected_regex, msg=None)` + +Fail the test unless the text matches the regular expression. + +`assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)` + +An equality assertion for ordered sequences (like lists and tuples). + +For the purposes of this function, a valid ordered sequence type is one which can be indexed, has a length, and has an equality operator. + +Parameters: + +* **seq1** – The first sequence to compare. +* **seq2** – The second sequence to compare. +* **seq_type** – The expected datatype of the sequences, or None if no datatype should be enforced. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertSetEqual(set1, set2, msg=None)` + +A set-specific equality assertion. + +Parameters: + +* **set1** – The first set to compare. +* **set2** – The second set to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +assertSetEqual uses ducktyping to support different types of sets, and is optimized for sets specifically (parameters must support a difference method). + +`assertSwitchState(name, state)` + +Assert that a switch exists and has a certain state. + +`assertTrue(expr, msg=None)` + +Check that the expression is true. + +`assertTupleEqual(tuple1, tuple2, msg=None)` + +A tuple-specific equality assertion. + +Parameters: + +* **tuple1** – The first tuple to compare. +* **tuple2** – The second tuple to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertWarns(expected_warning, *args, **kwargs)` + +Fail unless a warning of class warnClass is triggered by the callable when invoked with specified positional and keyword arguments. If a different type of warning is triggered, it will not be handled: depending on the other warning filtering rules in effect, it might be silenced, printed out, or raised as an exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertWarns(SomeWarning): + do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertWarns is used as a context object. + +The context manager keeps a reference to the first matching warning as the ‘warning’ attribute; similarly, the ‘filename’ and ‘lineno’ attributes give you information about the line of Python code from which the warning was triggered. This allows you to inspect the warning after the assertion: + +``` +with self.assertWarns(SomeWarning) as cm: + do_something() +the_warning = cm.warning +self.assertEqual(the_warning.some_attribute, 147) +``` + +`assertWarnsRegex(expected_warning, expected_regex, *args, **kwargs)` + +Asserts that the message in a triggered warning matches a regexp. Basic functioning is similar to assertWarns() with the addition that only warnings whose messages also match the regular expression are considered successful matches. + +Parameters: + +* **expected_warning** – Warning class expected to be triggered. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertWarnsRegex is used as a context manager. + +`fail(msg=None)` + +Fail immediately, with the given message. + +`static get_abs_path(path)` + +Get absolute path relative to current directory. + +`get_absolute_machine_path()` + +Return absolute machine path. + +`get_config_file()` + +Return a string name of the machine config file to use for the tests in this class. + +You should override this method in your own test class to point to the config file you need for your tests. +Returns: A string name of the machine config file to use, complete with the .yaml file extension. + +For example: + +``` +def get_config_file(self): +return 'my_config.yaml' +``` + +`get_enable_plugins()` + +Control whether tests in this class should load MPF plugins. + +Returns: True or False + +The default is False. To load plugins in your test class, add the following: + +``` +def get_enable_plugins(self): +return True +``` + +`get_machine_path()` + +Return a string name of the path to the machine folder to use for the tests in this class. + +You should override this method in your own test class to point to the machine folder root you need for your tests. +Returns: A string name of the machine path to use + +For example: + +``` +def get_machine_path(self): +return 'tests/machine_files/my_test/' +``` + +Note that this path is relative to the MPF package root + +`get_options()` + +Return options for the machine controller. + +`get_platform()` + +Force this test class to use a certain platform. +Returns: String name of the platform this test class will use. + +If you don’t include this method in your test class, the platform will be set to virtual. If you want to use the smart virtual platform, you would add the following to your test class: + +``` +def get_platform(self): + return 'smart_virtual` +``` + +`get_use_bcp()` + +Control whether tests in this class should use BCP. + +Returns: True or False + +The default is False. To use BCP in your test class, add the following: + +def get_use_bcp(self): +return True + +`hit_and_release_switch(name)` + +Momentarily activates and then deactivates a switch. + +Parameters: + +* **name** – The name of the switch to hit. + +This method immediately activates and deactivates a switch with no time in between. + +`hit_and_release_switches_simultaneously(names)` + +Momentarily activates and then deactivates multiple switches. + +Switches are hit sequentially and then released sequentially. Events are only processed at the end of the sequence which is useful to reproduce race conditions when processing nearly simultaneous hits. + +Parameters: + +* **names** – The names of the switches to hit and release. + +`hit_switch_and_run(name, delta)` + +Activates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +Note that this method does not deactivate the switch once the time has been advanced, meaning the switch stays active. To make the switch inactive, use the release_switch_and_run(). + +`machine_run()` + +Process any delays, timers, or anything else scheduled. + +Note this is the same as: + +self.advance_time_and_run(0) + +`mock_event(event_name)` + +Configure an event to be mocked. + +Parameters: + +* **event_name** – String name of the event to mock. + +Mocking an event is an easy way to check if an event was called without configuring some kind of callback action in your tests. + +Note that an event must be mocked here before it’s posted in order for assertEventNotCalled() and assertEventCalled() to work. + +Mocking an event will not “break” it. In other words, any other registered handlers for this event will also be called even if the event has been mocked. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will be True +self.post_event('my_event') +self.assertEventCalled('my_event') # This will also be True +``` + +`post_event(event_name, run_time=0)` + +Post an MPF event and optionally advance the time. + +Parameters: + +* **event_name** – String name of the event to post +* **run_time** – How much time (in seconds) the test should advance after this event has been posted. + +For example, to post an event called “shot1_hit”: + +self.post_event('shot1_hit') + +To post an event called “tilt” and then advance the time 1.5 seconds: + +self.post_event('tilt', 1.5) + +`post_event_with_params(event_name, **params)` + +Post an MPF event with kwarg parameters. + +Parameters: + +* **event_name** – String name of the event to post +* ****params** – One or more kwarg key/value pairs to post with the event. + +For example, to post an event called “jackpot” with the parameters count=1 and first_time=True, you would use: + +self.post_event('jackpot', count=1, first_time=True) + +`post_relay_event_with_params(event_name, **params)` + +Post a relay event synchronously and return the result. + +`release_switch_and_run(name, delta)` + +Deactivates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +`reset_mock_events()` + +Reset all mocked events. + +This will reset the count of number of times called every mocked event is. + +`restore_sys_path()` + +Restore sys path after test. + +`save_and_prepare_sys_path()` + +Save sys path and prepare it for the test. + +`setUp()` + +Setup test. + +`set_num_balls_known(balls)` + +Set the ball controller’s num_balls_known attribute. + +This is needed for tests where you don’t have any ball devices and other situations where you need the ball controller to think the machine has a certain amount of balls to run a test. + +Example: + +``` +self.set_num_balls_known(3) +``` + +`shortDescription()` + +Returns a one-line description of the test, or None if no description has been provided. + +The default implementation of this method returns the first line of the specified test method’s docstring. + +`skipTest(reason)` + +Skip this test. + +`start_mode(mode)` + +Start mode. + +`stop_mode(mode)` + +Stop mode. + +`tearDown()` + +Tear down test. + +`static unittest_verbosity()` + +Return the verbosity setting of the currently running unittest program, or 0 if none is running. + +Returns: An integer value of the current verbosity setting. + diff --git a/docs/code/api_reference/testing_class_api/MpfTestCase.md b/docs/code/api_reference/testing_class_api/MpfTestCase.md new file mode 100644 index 0000000000..d4d3ec9fe0 --- /dev/null +++ b/docs/code/api_reference/testing_class_api/MpfTestCase.md @@ -0,0 +1,656 @@ + +# MpfTestCase + +`class mpf.tests.MpfTestCase.MpfTestCase(methodName='runTest')` + +Bases: unittest.case.TestCase + +Primary TestCase class used for all MPF unit tests. + +## Methods & Attributes + +The MpfTestCase has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`static add_to_config_validator(machine, key, new_dict)` + +Add config dict to validator. + +`advance_time_and_run(delta=1.0)` + +Advance the test clock and run anything that should run during that time. +Parameters: delta – How much time to advance the test clock by (in seconds) + +This method will cause anything scheduled during the time to run, including things like delays, timers, etc. + +Advancing the clock will happen in multiple small steps if things are scheduled to happen during this advance. For example, you can advance the clock 10 seconds like this: + +``` +self.advance_time_and_run(10) +``` + +If there is a delay callback that is scheduled to happen in 2 seconds, then this method will advance the clock 2 seconds, process that delay, and then advance the remaining 8 seconds. + +`assertAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are unequal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is more than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +If the two objects compare equal then they will automatically compare almost equal. + +`assertAvailableBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is available on a playfield. + +`assertBallsOnPlayfield(balls, playfield='playfield')` + +Assert that a certain number of ball is on a playfield. + +`assertColorAlmostEqual(color1, color2, delta=6)` + +Assert that two color are almost equal. + +Parameters: + +* **color1** – The first color, as an RGBColor instance or 3-item iterable. +* **color2** – The second color, as an RGBColor instance or 3-item iterable. +* **delta** – How close the colors have to be. The deltas between red, green, and blue are added together and must be less or equal to this value for this assertion to succeed. + +`assertCountEqual(first, second, msg=None)` + +An unordered sequence comparison asserting that the same elements, regardless of order. If the same element occurs more than once, it verifies that the elements occur the same number of times. + +``` +self.assertEqual(Counter(list(first)), + Counter(list(second))) +``` + +Example: + +``` +[0, 1, 1] and [1, 0, 1] compare equal. +[0, 0, 1] and [0, 1] compare unequal. +``` + +`assertDictContainsSubset(subset, dictionary, msg=None)` + +Checks whether dictionary is a superset of subset. + +`assertEqual(first, second, msg=None)` + +Fail if the two objects are unequal as determined by the ‘==’ operator. + +`assertEventCalled(event_name, times=None)` + +Assert that event was called. + +Parameters: + +* **event_name** – String name of the event to check. +* **times** – An optional value to confirm the number of times the event was called. Default of None means this method will pass as long as the event has been called at least once. + +If you want to reset the times count, you can mock the event again. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 1) # This will pass + +self.post_event('my_event') +self.assertEventCalled('my_event') # This will pass +self.assertEventCalled('my_event', 2) # This will pass +``` + +`assertEventCalledWith(event_name, **kwargs)` + +Assert an event was called with certain kwargs. + +Parameters: + +* **event_name** – String name of the event to check. +* ****kwargs** – Name/value parameters to check. + +For example: + +``` +self.mock_event('jackpot') + +self.post_event('jackpot', count=1, first_time=True) +self.assertEventCalled('jackpot') # This will pass +self.assertEventCalledWith('jackpot', count=1, first_time=True) # This will also pass +self.assertEventCalledWith('jackpot', count=1, first_time=False) # This will fail +``` + +`assertEventNotCalled(event_name)` + +Assert that event was not called. + +Parameters: + +* **event_name** – String name of the event to check. + +Note that the event must be mocked via self.mock_event() first in order to use this method. + +`assertFalse(expr, msg=None)` + +Check that the expression is false. + +`assertGreater(a, b, msg=None)` + +Just like self.assertTrue(a > b), but with a nicer default message. + +`assertGreaterEqual(a, b, msg=None)` + +Just like self.assertTrue(a >= b), but with a nicer default message. + +`assertIn(member, container, msg=None)` + +Just like self.assertTrue(a in b), but with a nicer default message. + +`assertIs(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is b), but with a nicer default message. + +`assertIsInstance(obj, cls, msg=None)` + +Same as self.assertTrue(isinstance(obj, cls)), with a nicer default message. + +`assertIsNone(obj, msg=None)` + +Same as self.assertTrue(obj is None), with a nicer default message. + +`assertIsNot(expr1, expr2, msg=None)` + +Just like self.assertTrue(a is not b), but with a nicer default message. + +`assertIsNotNone(obj, msg=None)` + +Included for symmetry with assertIsNone. + +`assertLess(a, b, msg=None)` + +Just like self.assertTrue(a < b), but with a nicer default message. + +`assertLessEqual(a, b, msg=None)` + +Just like self.assertTrue(a <= b), but with a nicer default message. + +`assertLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel has a certain brightness. + +`assertLightColor(light_name, color)` + +Assert that a light exists and shows one color. + +`assertLightColors(light_name, color_list, secs=1, check_delta=0.1)` + +Assert that a light exists and shows all colors in a list over a period. + +`assertLightFlashing(light_name, color=None, secs=1, check_delta=0.1)` + +Assert that a light exists and is flashing. + +`assertLightOff(light_name)` + +Assert that a light exists and is off. + +`assertLightOn(light_name)` + +Assert that a light exists and is on. + +`assertListEqual(list1, list2, msg=None)` + +A list-specific equality assertion. + +Parameters: + +* **list1** – The first list to compare. +* **list2** – The second list to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertLogs(logger=None, level=None)` + +Fail unless a log message of level level or higher is emitted on logger_name or its children. If omitted, level defaults to INFO and logger defaults to the root logger. + +This method must be used as a context manager, and will yield a recording object with two attributes: output and records. At the end of the context manager, the output attribute will be a list of the matching formatted log messages and the records attribute will be a list of the corresponding LogRecord objects. + +Example: + +``` +with self.assertLogs('foo', level='INFO') as cm: + logging.getLogger('foo').info('first message') + logging.getLogger('foo.bar').error('second message') +self.assertEqual(cm.output, ['INFO:foo:first message', + 'ERROR:foo.bar:second message']) +``` + +`assertMachineVarEqual(value, machine_var)` + +Assert that a machine variable exists and has a certain value. + +`assertModeNotRunning(mode_name)` + +Assert that a mode exists and is not running. + +`assertModeRunning(mode_name)` + +Assert that a mode exists and is running. + +`assertMultiLineEqual(first, second, msg=None)` + +Assert that two multi-line strings are equal. + +`assertNotAlmostEqual(first, second, places=None, msg=None, delta=None)` + +Fail if the two objects are equal as determined by their difference rounded to the given number of decimal places (default 7) and comparing to zero, or by comparing that the difference between the two objects is less than the given delta. + +Note that decimal places (from zero) are usually not the same as significant digits (measured from the most significant digit). + +Objects that are equal automatically fail. + +`assertNotEqual(first, second, msg=None)` + +Fail if the two objects are equal as determined by the ‘!=’ operator. + +`assertNotIn(member, container, msg=None)` + +Just like self.assertTrue(a not in b), but with a nicer default message. + +`assertNotIsInstance(obj, cls, msg=None)` + +Included for symmetry with assertIsInstance. + +`assertNotLightChannel(light_name, brightness, channel='white')` + +Assert that a light channel does not have a certain brightness. + +`assertNotLightColor(light_name, color)` + +Assert that a light exists and does not show a certain color. + +`assertNotRegex(text, unexpected_regex, msg=None)` + +Fail the test if the text matches the regular expression. + +`assertNumBallsKnown(balls)` + +Assert that a certain number of balls are known in the machine. + +`assertPlaceholderEvaluates(expected, condition)` + +Assert that a placeholder evaluates to a certain value. + +`assertPlayerVarEqual(value, player_var)` + +Assert that a player variable exists and has a certain value. + +`assertRaises(expected_exception, *args, **kwargs)` + +Fail unless an exception of class expected_exception is raised by the callable when invoked with specified positional and keyword arguments. If a different type of exception is raised, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertRaises(SomeException): + do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertRaises is used as a context object. + +The context manager keeps a reference to the exception as the ‘exception’ attribute. This allows you to inspect the exception after the assertion: + +``` +with self.assertRaises(SomeException) as cm: + do_something() +the_exception = cm.exception +self.assertEqual(the_exception.error_code, 3) +``` + +`assertRaisesRegex(expected_exception, expected_regex, *args, **kwargs)` + +Asserts that the message in a raised exception matches a regex. + +Parameters: + +* **expected_exception** – Exception class expected to be raised. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertRaisesRegex is used as a context manager. + +`assertRegex(text, expected_regex, msg=None)` + +Fail the test unless the text matches the regular expression. + +`assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)` + +An equality assertion for ordered sequences (like lists and tuples). + +For the purposes of this function, a valid ordered sequence type is one which can be indexed, has a length, and has an equality operator. + +Parameters: + +* **seq1** – The first sequence to compare. +* **seq2** – The second sequence to compare. +* **seq_type** – The expected datatype of the sequences, or None if no datatype should be enforced. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertSetEqual(set1, set2, msg=None)` + +A set-specific equality assertion. + +Parameters: + +* **set1** – The first set to compare. +* **set2** – The second set to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +assertSetEqual uses ducktyping to support different types of sets, and is optimized for sets specifically (parameters must support a difference method). + +`assertSwitchState(name, state)` + +Assert that a switch exists and has a certain state. + +`assertTrue(expr, msg=None)` + +Check that the expression is true. + +`assertTupleEqual(tuple1, tuple2, msg=None)` + +A tuple-specific equality assertion. + +Parameters: + +* **tuple1** – The first tuple to compare. +* **tuple2** – The second tuple to compare. +* **msg** – Optional message to use on failure instead of a list of differences. + +`assertWarns(expected_warning, *args, **kwargs)` + +Fail unless a warning of class warnClass is triggered by the callable when invoked with specified positional and keyword arguments. If a different type of warning is triggered, it will not be handled: depending on the other warning filtering rules in effect, it might be silenced, printed out, or raised as an exception. + +If called with the callable and arguments omitted, will return a context object used like this: + +``` +with self.assertWarns(SomeWarning): + do_something() +``` + +An optional keyword argument ‘msg’ can be provided when assertWarns is used as a context object. + +The context manager keeps a reference to the first matching warning as the ‘warning’ attribute; similarly, the ‘filename’ and ‘lineno’ attributes give you information about the line of Python code from which the warning was triggered. This allows you to inspect the warning after the assertion: + +``` +with self.assertWarns(SomeWarning) as cm: + do_something() +the_warning = cm.warning +self.assertEqual(the_warning.some_attribute, 147) +``` + +`assertWarnsRegex(expected_warning, expected_regex, *args, **kwargs)` + +Asserts that the message in a triggered warning matches a regexp. Basic functioning is similar to assertWarns() with the addition that only warnings whose messages also match the regular expression are considered successful matches. + +Parameters: + +* **expected_warning** – Warning class expected to be triggered. +* **expected_regex** – Regex (re.Pattern object or string) expected to be found in error message. +* **args** – Function to be called and extra positional args. +* **kwargs** – Extra kwargs. +* **msg** – Optional message used in case of failure. Can only be used when assertWarnsRegex is used as a context manager. + +`fail(msg=None)` + +Fail immediately, with the given message. + +`static get_abs_path(path)` + +Get absolute path relative to current directory. + +`get_absolute_machine_path()` + +Return absolute machine path. + +`get_config_file()` + +Return a string name of the machine config file to use for the tests in this class. + +You should override this method in your own test class to point to the config file you need for your tests. +Returns: A string name of the machine config file to use, complete with the .yaml file extension. + +For example: + +``` +def get_config_file(self): + return 'my_config.yaml' +``` + +`get_enable_plugins()`` + +Control whether tests in this class should load MPF plugins. + +Returns: True or False + +The default is False. To load plugins in your test class, add the following: + +``` +def get_enable_plugins(self): + return True +``` + +`get_machine_path()` + +Return a string name of the path to the machine folder to use for the tests in this class. + +You should override this method in your own test class to point to the machine folder root you need for your tests. +Returns: A string name of the machine path to use + +For example: + +``` +def get_machine_path(self): + return 'tests/machine_files/my_test/' +``` + +Note that this path is relative to the MPF package root + +`get_options()` + +Return options for the machine controller. + +`get_platform()` + +Force this test class to use a certain platform. +Returns: String name of the platform this test class will use. + +If you don’t include this method in your test class, the platform will be set to virtual. If you want to use the smart virtual platform, you would add the following to your test class: + +def get_platform(self): + return 'smart_virtual' + +`get_use_bcp()` + +Control whether tests in this class should use BCP. + +Returns: True or False + +The default is False. To use BCP in your test class, add the following: + +``` +def get_use_bcp(self): + return True +``` + +`hit_and_release_switch(name)` + +Momentarily activates and then deactivates a switch. + +Parameters: + +* **name** – The name of the switch to hit. + +This method immediately activates and deactivates a switch with no time in between. + +`hit_and_release_switches_simultaneously(names)` + +Momentarily activates and then deactivates multiple switches. + +Switches are hit sequentially and then released sequentially. Events are only processed at the end of the sequence which is useful to reproduce race conditions when processing nearly simultaneous hits. + +Parameters: + +* **names** – The names of the switches to hit and release. + +`hit_switch_and_run(name, delta)` + +Activates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +Note that this method does not deactivate the switch once the time has been advanced, meaning the switch stays active. To make the switch inactive, use the release_switch_and_run(). + +`machine_run()` + +Process any delays, timers, or anything else scheduled. + +Note this is the same as: + +self.advance_time_and_run(0) + +`mock_event(event_name)` + +Configure an event to be mocked. + +Parameters: + +* **event_name** – String name of the event to mock. + +Mocking an event is an easy way to check if an event was called without configuring some kind of callback action in your tests. + +Note that an event must be mocked here before it’s posted in order for assertEventNotCalled() and assertEventCalled() to work. + +Mocking an event will not “break” it. In other words, any other registered handlers for this event will also be called even if the event has been mocked. + +For example: + +``` +self.mock_event('my_event') +self.assertEventNotCalled('my_event') # This will be True +self.post_event('my_event') +self.assertEventCalled('my_event') # This will also be True +``` + +`post_event(event_name, run_time=0)` + +Post an MPF event and optionally advance the time. + +Parameters: + +* **event_name** – String name of the event to post +* **run_time** – How much time (in seconds) the test should advance after this event has been posted. + +For example, to post an event called “shot1_hit”: + +self.post_event('shot1_hit') + +To post an event called “tilt” and then advance the time 1.5 seconds: + +self.post_event('tilt', 1.5) + +`post_event_with_params(event_name, **params)` + +Post an MPF event with kwarg parameters. + +Parameters: + +* **event_name** – String name of the event to post +* ****params** – One or more kwarg key/value pairs to post with the event. + +For example, to post an event called “jackpot” with the parameters count=1 and first_time=True, you would use: + +``` +self.post_event('jackpot', count=1, first_time=True) +``` + +`post_relay_event_with_params(event_name, **params)` + +Post a relay event synchronously and return the result. + +`release_switch_and_run(name, delta)` + +Deactivates a switch and advances the time. + +Parameters: + +* **name** – The name of the switch to activate. +* **delta** – The time (in seconds) to advance the clock. + +`reset_mock_events()` + +Reset all mocked events. + +This will reset the count of number of times called every mocked event is. + +`restore_sys_path()` + +Restore sys path after test. + +`save_and_prepare_sys_path()` + +Save sys path and prepare it for the test. + +`setUp()` + +Setup test. + +`set_num_balls_known(balls)` + +Set the ball controller’s num_balls_known attribute. + +This is needed for tests where you don’t have any ball devices and other situations where you need the ball controller to think the machine has a certain amount of balls to run a test. + +Example: + +``` +self.set_num_balls_known(3) +``` + +`shortDescription()` + +Returns a one-line description of the test, or None if no description has been provided. + +The default implementation of this method returns the first line of the specified test method’s docstring. + +`skipTest(reason)` + +Skip this test. + +`start_mode(mode)` + +Start mode. + +`stop_mode(mode)` + +Stop mode. + +`tearDown()` + +Tear down test. + +`static unittest_verbosity()` + +Return the verbosity setting of the currently running unittest program, or 0 if none is running. + +Returns: An integer value of the current verbosity setting. + diff --git a/docs/code/api_reference/testing_class_api/TestDataManager.md b/docs/code/api_reference/testing_class_api/TestDataManager.md new file mode 100644 index 0000000000..ee41885ff3 --- /dev/null +++ b/docs/code/api_reference/testing_class_api/TestDataManager.md @@ -0,0 +1,47 @@ + +# TestDataManager + +`class mpf.tests.TestDataManager.TestDataManager(data)` + +Bases: mpf.core.data_manager.DataManager + +A patched version of the DataManager which is used in unit tests. + +The main change is that the `save_all()` method doesn’t actually write anything to disk so the tests don’t fill up the disk with unneeded data. + +## Methods & Attributes + +The TestDataManager has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_data(section=None)` + +Return the value of this DataManager’s data. + +Parameters: + +* **section** – Optional string name of a section (dictionary key) for the data you want returned. Default is None which returns the entire dictionary. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`save_all(data)` + +Update all data. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/testing_class_api/TestMachineController.md b/docs/code/api_reference/testing_class_api/TestMachineController.md new file mode 100644 index 0000000000..90734b9a4b --- /dev/null +++ b/docs/code/api_reference/testing_class_api/TestMachineController.md @@ -0,0 +1,142 @@ + +# TestMachineController + +`class mpf.tests.MpfTestCase.TestMachineController(options, config, config_patches, config_defaults, clock, mock_data, enable_plugins=False)` + +Bases: `mpf.core.machine.MachineController` + +A patched version of the MachineController used in tests. + +The TestMachineController has a few changes from the regular machine controller to facilitate running unit tests, including: + +* Use the TestDataManager instead of the real one. +* Use a test clock which we can manually advance instead of the regular clock tied to real-world time. +* Only load plugins if self._enable_plugins is True. +* Merge any test_config_patches into the machine config. +* Disabled the config file caching to always load the config from disk. + +## Methods & Attributes + +The TestMachineController has the following methods & attributes available. Note that methods & attributes inherited from the base class are not included here. + +`add_crash_handler(handler: Callable)` + +Add a crash handler which is called on a crash. + +This can be used to restore the output and prepare logging. + +`add_platform(name: str) → None` + +Make an additional hardware platform interface available to MPF. + +Parameters: + +* **name** – String name of the platform to add. Must match the name of a platform file in the mpf/platforms folder (without the .py extension). + +`clear_boot_hold(hold: str) → None` + +Clear a boot hold. + +`create_data_manager(config_name)` + +Create TestDataManager. + +`format_log_line(msg, context, error_no) → str` + +Return a formatted log line with log link and context. + +`get_platform_sections(platform_section: str, overwrite: str) → SmartVirtualHardwarePlatform` + +Return platform section. + +`ignorable_runtime_exception(msg: str) → None` + +Handle ignorable runtime exception. + +During development or tests raise an exception for easier debugging. Log an error during production. + +`init_done() → None` + +Finish init. + +Called when init is done and all boot holds are cleared. + +`initialise() → None` + +Initialise machine. + +`initialise_core_and_hardware() → None` + +Load core modules and hardware. + +`initialise_mpf()` + +Initialise MPF. + +`raise_config_error(msg, error_no, *, context=None) → NoReturn` + +Raise a ConfigFileError exception. + +`register_boot_hold(hold: str) → None` + +Register a boot hold. + +`register_monitor(monitor_class: str, monitor: Callable[[...], Any]) → None` + +Register a monitor. + +Parameters: + +* **monitor_class** – String name of the monitor class for this monitor that’s being registered. +* **monitor** – Callback to notify + +MPF uses monitors to allow components to monitor certain internal elements of MPF. + +For example, a player variable monitor could be setup to be notified of any changes to a player variable, or a switch monitor could be used to allow a plugin to be notified of any changes to any switches. + +The MachineController’s list of registered monitors doesn’t actually do anything. Rather it’s a dictionary of sets which the monitors themselves can reference when they need to do something. We just needed a central registry of monitors. + +`reset() → None` + +Reset the machine. + +This method is safe to call. It essentially sets up everything from scratch without reloading the config files and assets from disk. This method is called after a game ends and before attract mode begins. + +`run() → None` + +Start the main machine run loop. + +`set_default_platform(name: str) → None` + +Set the default platform. + +It is used if a device class-specific or device-specific platform is not specified. + +Parameters: + +* **name** – String name of the platform to set to default. + +`shutdown() → None` + +Shutdown the machine. + +`stop(reason=None, **kwargs) → None` + +Perform a graceful exit of MPF. + +`validate_machine_config_section(section: str) → None` + +Validate a config section. + +`verify_system_info()` + +Dump information about the Python installation to the log. + +Information includes Python version, Python executable, platform, and core architecture. + +`warning_log(msg: str, *args, context=None, error_no=None, **kwargs) → None` + +Log a message at the warning level. + +These messages will always be shown in the console and the log file. + diff --git a/docs/code/api_reference/testing_class_api/test_classes.png b/docs/code/api_reference/testing_class_api/test_classes.png new file mode 100644 index 0000000000..2cac64d1e0 Binary files /dev/null and b/docs/code/api_reference/testing_class_api/test_classes.png differ diff --git a/docs/code/api_reference/testing_class_api/test_classes.webp b/docs/code/api_reference/testing_class_api/test_classes.webp new file mode 100644 index 0000000000..f20022682a Binary files /dev/null and b/docs/code/api_reference/testing_class_api/test_classes.webp differ diff --git a/docs/code/index.md b/docs/code/index.md new file mode 100644 index 0000000000..10cf924248 --- /dev/null +++ b/docs/code/index.md @@ -0,0 +1,18 @@ +--- +title: "Adding custom code to your game" +--- + +# Adding custom code to your game + +While one of the goals of MPF is to allow you to do as much of your game’s configuration as possible with the config files, we recognize that many people will want to mix in some custom code to their machines. + +Fortunately that’s easy to do, and you don’t have to “hack” MPF or break anything to make it happen! + +The amount of custom code you use is up to you, depending on your personal preferences, your comfort with Python, and what exactly you want to do with your machine. + +Some people will use the config files for 99% of their machine, and only add a little custom code here and there. Others will only want to use the configs for the “basic” stuff and then write all their game logic in Python. Either option is fine with us! + +When you decide that you want to add some custom Python code into your game, there are two ways you can do this: + +* Mode-specific code, which allows you to write custom Python code which is only active when a particular game mode is active. +* Machine-wide code, useful for dealing with custom hardware, like the crane in Demolition Man. diff --git a/docs/code/introduction/debug.md b/docs/code/introduction/debug.md new file mode 100644 index 0000000000..1cd3366c15 --- /dev/null +++ b/docs/code/introduction/debug.md @@ -0,0 +1,42 @@ +# Debugging + +At some point in time you might have to debug either your own code or you want to debug the orginal MPF code. For this of course a Python debugger is needed. You can use your preferred tool and are not bound to a specific tool. In this chapter the debugging is explained using the [PyCharm Community Edition](https://www.jetbrains.com/pycharm/download/other.html). Regardless if you want to debug your own code or the MPF code itself, the process is the same and you can follow these instructions. + +## Basic Setup +First of all you need to install MPF using a virtual environment and not using a precompile package, follow the [install chapter](../../install/index.md) for this. Then of course you need to install PyCharm, there is not much to do to install PyCharm after the download just run the installer. + + +## Open Project in PyCharm +Open the folder structure in PyCharm where you source file is located you would like to debug, that might be your machine folder with your own code extension or it might be the mpf sources which are located inside your virtual environment. From the `File` menu select `open`, if you don't see the `File` menu you have to click the three horizontal lines (Hamburger button) to make the menu visible. + +A pop-up window will open, now either navigate and select your machine folder or your virtual environment folder: + +![open menu](images/debug_open_project.png) + +## Set breakpoint + +On the left side you will find the file structure, here you need to navigate to the source file you want to debug. Open that file in the code editor. + +By clicking on the line number you can set a breakpoint: + +![open menu](images/debug_set_breakpoint.png) + +## Attach to process + +Now it is time to start mpf like you normally do. Keep in mind, that before you start mpf with e.g. `mpf -t -b`, that you need to [activate](../../install/virtual-environments.md) your Python virtual environment. + +From the `Run` menu select `Attach to Process` + +![open menu](images/debug_attach.png) + +Afterwards a new pop-up window will open up + +![open menu](images/debug_select_process.png) + +from where you need to select your mpf process, depeding what other (Python) process you have running the list might be shorter or longer. + +## Start Debugging + +Run your game and wait until your game flow hits the debugger. Now you have the normal debugging options like stepping in or looking into variables. + +![open menu](images/debug_code.png) diff --git a/docs/code/introduction/images/debug_attach.png b/docs/code/introduction/images/debug_attach.png new file mode 100644 index 0000000000..82d7b38299 Binary files /dev/null and b/docs/code/introduction/images/debug_attach.png differ diff --git a/docs/code/introduction/images/debug_code.png b/docs/code/introduction/images/debug_code.png new file mode 100644 index 0000000000..3793e82b44 Binary files /dev/null and b/docs/code/introduction/images/debug_code.png differ diff --git a/docs/code/introduction/images/debug_open_project.png b/docs/code/introduction/images/debug_open_project.png new file mode 100644 index 0000000000..f3de6fef51 Binary files /dev/null and b/docs/code/introduction/images/debug_open_project.png differ diff --git a/docs/code/introduction/images/debug_select_process.png b/docs/code/introduction/images/debug_select_process.png new file mode 100644 index 0000000000..f5a25af883 Binary files /dev/null and b/docs/code/introduction/images/debug_select_process.png differ diff --git a/docs/code/introduction/images/debug_set_breakpoint.png b/docs/code/introduction/images/debug_set_breakpoint.png new file mode 100644 index 0000000000..a1671a8a0a Binary files /dev/null and b/docs/code/introduction/images/debug_set_breakpoint.png differ diff --git a/docs/code/introduction/index.md b/docs/code/introduction/index.md new file mode 100644 index 0000000000..9c7106faa9 --- /dev/null +++ b/docs/code/introduction/index.md @@ -0,0 +1,16 @@ +# Introduction + +This introduction chapter should give you a quick start into extending MPF. + +!!! note "Mode custom code vs. machine custom code" + + Note that MPF also has the ability to run custom mode code which is code that is associated with a certain game mode and is generally only active when the mode it’s in is active. So if you just want to write your own custom game logic, you’ll probably use mode code. MPF has well the ability to run machine wide code, which is active as long as MPF is running regardless of the mode you are in. You need to decide what code extension you need. + +Follow either the examples for the [machine wide](machine_code.md) extension or the [mode wide](mode_code.md) extension. In the next step most extensions probably have to deal in one or the other way with variables, follow this [variable guide](variables_in_code.md) to learn how to deal with MPF variables in your own code. + +As long as you only write smaller extensions you don't have to setup a full Python development environment. Of course you can and the more complex your development gets the more handy it might be. The [setup guide](setup.md) you only have to follow if you really want to develop MPF itself and not only to write an extension for your game. + +Last but not least of course the [API Reference](../api_reference/index.md) is very important for you. + + + diff --git a/docs/code/introduction/machine_code.md b/docs/code/introduction/machine_code.md new file mode 100644 index 0000000000..b3c09c0098 --- /dev/null +++ b/docs/code/introduction/machine_code.md @@ -0,0 +1,255 @@ +--- +title: "How to add machine-wide custom code" +--- + + +# How to add machine-wide custom code + +MPF contains a “CustomCode” concept which lets you add custom code to your game. + +CustomCode classes are Python modules that run at the “root” of your game. You can use them to do anything you want. + +CustomCode classes are sort of “machine-level” custom code. CustomCode classes are nice if you have some kind of custom device type that doesn’t match up to any of MPF’s built in devices. The elevator and claw unloader in Demolition Man is a good example, and what we’ll use here. + +(You can read about how to download and run Demo Man in the example games section section of the MPF User Documentation.) + +Here’s how to create a custom code class: +## Create your custom code file + +First, add a `custom_code` folder to your machine folder. Then inside there, create the Python file that will hold your custom code classes. + +All your classes will be referenced as `custom_code.file_name.ClassName`. + +## Open and edit your custom code class file + +Next, edit the class file you created. At a bare minimum, you’ll need this: + +``` +from mpf.core.custom_code import CustomCode + +class Claw(CustomCode): + pass +``` + +Note that MPF contains a CustomCode base class which is very simple. You can see the [CustomCode source](https://github.com/missionpinball/mpf/blob/dev/mpf/core/custom_code.py) on GitHub. We called our class Claw in this case. + +Pretty much all this does is give you a reference to the main MPF machine controller at `self.machine`, as well as setup a delay manager you can use and set the name of your class. There’s also an `on_load()` method which is called when the class is loaded which you can use in your own code. + +## Add the class to your machine config + +Next, edit your machine config file and add a `custom_code:` section, then under there add the package (folder), followed by a dot, then the module (file name) for your class, followed by a dot, followed by the class name for your class. + +For Demo Man, that looks like this: + +``` +custom_code: + - custom_code.claw.Claw +``` + +This references class Claw in file claw.py which lives package custom_code. + +## Real-world example + +At this point you should be able to run your game, though nothing should happen because you haven’t added any code to your code. + +Take a look at the final Demo Man claw class to see what we did there. Since custom code classes have access to self.machine and they load when MPF loads, you can do anything you want in them. + + +``` +from mpf.core.custom_code import CustomCode + + +class Claw(CustomCode): + + def on_load(self): + + self.auto_release_in_progress = False + + # if the elevator switch is active for more than 100ms, that means + # a ball is there, so we want to get it and deliver it to the claw + self.machine.switch_controller.add_switch_handler( + 's_elevator_hold', self.get_ball, ms=100) + + # This is a one-time thing to check to see if there's a ball in + # the elevator when MPF starts, and if so, we want to get it. + if self.machine.switch_controller.is_active('s_elevator_hold'): + self.auto_release_in_progress = True + self.get_ball() + + # We'll use the event 'light_claw' to light the claw, so in the + # future all we have to do is post this event and everything else + # will be automatic. + self.machine.events.add_handler('light_claw', self.light_claw) + + def enable(self): + """Enable the claw.""" + + # move left & right with the flipper switches, and stop moving when + # they're released + + self.machine.switch_controller.add_switch_handler( + 's_flipper_lower_left', self.move_left) + self.machine.switch_controller.add_switch_handler( + 's_flipper_lower_left', self.stop_moving, state=0) + self.machine.switch_controller.add_switch_handler( + 's_flipper_lower_right', self.move_right) + self.machine.switch_controller.add_switch_handler( + 's_flipper_lower_right', self.stop_moving, state=0) + + # release the ball when the launch button is hit + self.machine.switch_controller.add_switch_handler( + 's_ball_launch', self.release) + + # stop moving if the claw hits a limit switch + self.machine.switch_controller.add_switch_handler( + 's_claw_position_1', self.stop_moving) + + # We can use this event for slides to explain what's going on for + # the player. + self.machine.events.post('claw_enabled') + + def disable(self): + """Disable the claw.""" + + self.stop_moving() + + # remove all the switch handlers + self.machine.switch_controller.remove_switch_handler( + 's_flipper_lower_left', self.move_left) + self.machine.switch_controller.remove_switch_handler( + 's_flipper_lower_left', self.stop_moving, state=0) + self.machine.switch_controller.remove_switch_handler( + 's_flipper_lower_right', self.move_right) + self.machine.switch_controller.remove_switch_handler( + 's_flipper_lower_right', self.stop_moving, state=0) + self.machine.switch_controller.remove_switch_handler( + 's_ball_launch', self.release) + self.machine.switch_controller.remove_switch_handler( + 's_claw_position_1', self.stop_moving) + self.machine.switch_controller.remove_switch_handler( + 's_claw_position_1', self.release, state=0) + self.machine.switch_controller.remove_switch_handler( + 's_claw_position_2', self.release) + + self.machine.events.post('claw_disabled') + + def move_left(self): + """Start the claw moving to the left.""" + # before we turn on the driver to move the claw, make sure we're not + # at the left limit + if (self.machine.switch_controller.is_active('s_claw_position_2') and + self.machine.switch_controller.is_active('s_claw_position_1')): + return + self.machine.coils['c_claw_motor_left'].enable() + + def move_right(self): + """Start the claw moving to the right.""" + # before we turn on the driver to move the claw, make sure we're not + # at the right limit + if (self.machine.switch_controller.is_active('s_claw_position_1') and + self.machine.switch_controller.is_inactive('s_claw_position_2')): + return + self.machine.coils['c_claw_motor_right'].enable() + + def stop_moving(self): + """Stop the claw moving.""" + self.machine.coils['c_claw_motor_left'].disable() + self.machine.coils['c_claw_motor_right'].disable() + + def release(self): + """Release the ball by disabling the claw magnet.""" + self.disable_claw_magnet() + self.auto_release_in_progress = False + + # Disable the claw since it doesn't have a ball anymore + self.disable() + + def auto_release(self): + """Aumatically move and release the ball.""" + # disable the switches since the machine is in control now + self.disable() + + # If we're at the left limit, we need to move right before we can + # release the ball. + if (self.machine.switch_controller.is_active('s_claw_position_2') and + self.machine.switch_controller.is_active('s_claw_position_1')): + self.machine.switch_controller.add_switch_handler( + 's_claw_position_1', self.release, state=0) + # move right, drop when switch 1 opens + self.move_right() + + # If we're at the right limit, we need to move left before we can + # release the ball + elif (self.machine.switch_controller.is_active('s_claw_position_1') and + self.machine.switch_controller.is_inactive('s_claw_position_2')): + self.machine.switch_controller.add_switch_handler( + 's_claw_position_2', self.release) + # move left, drop when switch 2 closes + self.move_left() + + # If we're not at any limit, we can release the ball now. + else: + self.release() + + def get_ball(self): + """Get a ball from the elevator.""" + + # If there's no game in progress, we're going to auto pickup and + # drop the ball with no player input + + if not self.machine.game: + self.auto_release_in_progress = True + + # If the claw is not already in the ball pickup position, then move it + # to the right. + if not (self.machine.switch_controller.is_active('s_claw_position_1') and + self.machine.switch_controller.is_inactive('s_claw_position_2')): + self.move_right() + + self.machine.switch_controller.add_switch_handler( + 's_claw_position_1', self.do_pickup) + + # If the claw is in position for a pickup, we can do that pickup now + else: + self.do_pickup() + + def do_pickup(self): + """Pickup a ball from the elevator""" + self.stop_moving() + self.machine.switch_controller.remove_switch_handler( + 's_claw_position_1', self.do_pickup) + self.enable_claw_magnet() + self.machine.coils['c_elevator_motor'].enable() + self.machine.switch_controller.add_switch_handler('s_elevator_index', + self.stop_elevator) + + # If this is not an auto release, enable control of the claw for the + # player + if not self.auto_release_in_progress: + self.enable() + + def stop_elevator(self): + """Stop the elevator.""" + self.machine.coils['c_elevator_motor'].disable() + + if self.auto_release_in_progress: + self.auto_release() + + def light_claw(self, **kwargs): + """Lights the claw.""" + + # Lighting the claw just enables the diverter so that the ball shot + # that way will go to the elevator. Once the ball hits the elevator, + # the other methods kick in to deliver it to the claw, and then once + # the claw has it, the player can move and release it on their own. + self.machine.diverters['diverter'].enable() + + def disable_claw_magnet(self): + """Disable the claw magnet.""" + self.machine.coils['c_claw_magnet'].disable() + + def enable_claw_magnet(self): + """Enable the claw magnet.""" + self.machine.coils['c_claw_magnet'].enable() + +``` diff --git a/docs/code/introduction/mode_code.md b/docs/code/introduction/mode_code.md new file mode 100644 index 0000000000..ce39415db0 --- /dev/null +++ b/docs/code/introduction/mode_code.md @@ -0,0 +1,142 @@ +--- +title: "How to add custom Python code to a game mode" +--- + + +# How to add custom Python code to a game mode + +The easiest and most common way to add custom Python code into your MPF game is to add a code module to a mode folder. That lets you run code when that mode is active and helps you break up any custom code you write per mode. + +This “mode code” (as we call it) has access to the full MPF API. You can post events, register event handlers which run custom things when events are posted, access device state and control devices, read and set player variables, post slides… really anything MPF can do, you can do. + +Here’s how you get started with custom mode code. + +## Create the module (file) to hold you code + +First, go into the mode folder where you want to create your custom code, and add a “code” folder to that mode folder. Then inside that folder, create a file (we usually give this file the same name as the mode) with a .py extension. + +For example, if you wanted to create custom code for your base mode, it might look like this: + +``` + +├── config +└── modes + ├── attract + └── base + ├── config + │ └── base.yaml + └── code + └── base.py +``` + +## Open up the new Python file you just created + +Next, open the new mode code Python file you just created and add the bare minimum, which would look like this: + +``` +from mpf.core.mode import Mode + +class Base(Mode): + pass +``` + +MPF includes a Mode class which acts as the base class for every mode that runs in a game. That base class lives in the MPF package at mpf.core.mode. You can see it online in GitHub [here](https://github.com/missionpinball/mpf/blob/dev/mpf/core/mode.py). + +Notice that we named our custom class Base. You can name it whatever you want. + +## Update your mode config file to use the custom code + +Once you create your custom mode code, you need to tell MPF that this mode uses custom code instead of just the built-in code. + +To do this, add a `code:` entry into the mode config file for the mode where you’re adding custom code. So in this case, that would be in the `/modes/base/config/base.yaml` file, like this: + +``` +mode: + start_events: ball_starting + priority: 100 + code: base.Base +``` + +Note that the value for the `code:` section is the name of the Python module (the file), then a dot, then the name of the class from that file. So in this case, that’s base.Base. + +## Run your game! + +At this point you should be able to run your game and nothing should happen. This is good, because if it doesn’t crash, that means you did everything right. Of course nothing special happens because you didn’t actually add any code to your custom mode code, so you won’t see anything different. + +## Add some custom methods to do things + +You can look at the Mode base class (the link from GitHub from earlier) to see what the base Mode class does. However, we have created a few “convenience” methods that you can use. They are: + +* **mode_init:** Called once when MPF is starting up + +* **mode_start:** Called every time the mode starts, just after the mode__started event is posted. + +* **add_mode_event_handler:** This is the same as the main add_event_handler() method from the Event Manager, except since it’s mode-specific it will also automatically remove any event handlers that you registered when the mode stops. (If you want to register event handlers that are always watching for events even when the mode is not running, you can use the regular `self.machine.mode.add_handler()` method. + +You don’t have to use all of these if you don’t want to. + +Also, modes have additional convenience attributes you can use within your mode code: + +* **self.config:** A link to the config dictionary for the mode’s config file. + +* **self.priority:** The priority the mode is running at. (Don’t change this. Just read it.) + + +* **self.delay:** An instance of the delay manager you can use to set delayed callbacks for this mode. Any active ones will be automatically removed when the mode ends. + +* **self.player:** A link to the current player object that’s automatically updated when the player changes. This will be None if the mode is running outside of a game. + +* **self.active:** A boolean (True/False) value you can query to see if the mode is running. + +## Example usage + +Here’s an example of some mode code in use. This example is just a bunch of random things, but again, since you’re writing code here, the sky’s the limit! Seriously you could do all your game logic in mode code and not use the MPF configs at all if you wanted to. + + +``` +from mpf.core.mode import Mode + + +class Base(Mode): + + def mode_init(self): + self.machine.log.info("My custom mode code is being initialized") + #Technically the Python print command works as well, but make it a habit to log properly + + def mode_start(self, **kwargs): + # The mode_start method needs **kwargs because some events that + # start modes pass additional parameters + + self.machine.log.info("My custom mode code is starting") + + # Set a delay to call self.my_callback() in 5 seconds + self.delay.add(5000, self.my_callback) + + # what player are we? + self.machine.log.info(self.player.number) + + # what's the player's score? + self.machine.log.info('Score: {}'.format(self.player.score)) + + self.add_mode_event_handler('player_score', self.player_score_change) + + # turn LED "led01" red + self.machine.leds.led01.color('red') + + def my_callback(self): + self.machine.log.info("My delayed call was just called!") + + def player_score_change(self, **kwargs): + #Option 1 to log the score using kwargs + self.machine.log.info("Player score went up by %s, was %s and is now %s", kwargs['change'], kwargs['prev_value'], kwargs['value']) + #Option 2 to log the score using the player variable + self.machine.log.info("The new player's score is {}".format(self.player.score)) + + def mode_stop(self, **kwargs): + # The mode_stop method needs **kwargs because some events that + # stop modes pass additional parameters + + self.machine.log.info("My custom mode code is stopping") +``` + +You can use the API reference (or just look at the source code) to see what options exist. Really you can do anything you want. diff --git a/docs/code/introduction/setup.md b/docs/code/introduction/setup.md new file mode 100644 index 0000000000..cb37ac0f6f --- /dev/null +++ b/docs/code/introduction/setup.md @@ -0,0 +1,100 @@ + +# Setting up your MPF Dev Environment + +!!! note "MPF 0.80 installation update" + + The following section should not be necessary anymore if you follow the virtual standard installation + of MPF 0.80, see [here](../../install/index.md). Do not install the precompiled binaries if you plan to develop. + + +If you want to work on the core MPF or MPF-MC code, you have to install MPF and MPF-MC a bit differently than the normal process. + +Why? Because normally when you install MPF and MPF-MC via pip, they get installed as Python packages into your Python/Lib/site-packages folder, and that location is not too conducive to editing MPF source code since it’s in a deep random location. Also, if you ever ran pip again to update your MPF installation, you would potentially overwrite any changes you made. + +Instead, you need to install MPF and MPF-MC in “developer” (also known as “editable”) mode. This mode will let you run MPF and MPF-MC from the folder of your choice, and will allow code changes or additions you make to be immediately available whenever you run MPF. + +## 1. Install a git client + +MPF is cross-platform and runs the same on Mac, Windows, or Linux. So any changes or additions you make should work on all platforms. + +If you’re on Windows or Mac, the easiest way to get a git client installed is to use the GitHub Desktop app. This app will also install the git command line tools. + +## 2. Clone the MPF and/or MPF-MC repo(s) + +Clone the mpf repository and its submodules : + +``` +git clone --recursive https://github.com/missionpinball/mpf.git +``` + +Same thing for the mpf-mc repository : + +``` +git clone --recursive https://github.com/missionpinball/mpf-mc.git +``` + +If you’re using the GitHub Desktop app, you can also browse to the repos on GitHub and click the green “Clone or Download” button, and then click the “Open in Desktop” link. That will pop up a box that prompts you to pick a folder for the local codebase. + +Then inside that folder, you’ll end up with an mpf folder for MPF and mpf-mc folder for MPF-MC. + +## 3. Install MPF / MPF-MC in “developer” mode + +Create a “virtualenv” for your MPF development in a mpf-env directory (Note : if you don’t have virtualenv installed, you can get it via pip by running pip3 install virtualenv. + +Using virtualenv lets you keep all the other Python packages MPF needs (pyserial, pyyaml, kivy, etc.) together in a “virtual” environment that you’ll use for MPF and helps keep everything in your Python environment cleaner in general. + +Create a new virtualenv called “mpf-venv” (or whatever you want to name it) like this: + +``` +virtualenv -p python3 mpf-venv +``` + +Then enter the newly-created virtualenv: + +``` +source mpf-venv/bin/activate +``` + +On Macs, you will need to uninstall and reinstall kivy in the the virtual envirment to avoid ambiguous kivy library errors. + +1) pip uninstall kivy +2) pip install kivy -no-binary :all: + +Each time you’ll work with your MPF development version you’ll have to switch to this environment. + +``` +source mpf-venv/bin/activate +``` + +Note: in this environment, thanks to the “-p python3” option of virtualenv, the version of Python and pip is 3.x automatically. + +Next you’ll install MPF and MPF-MC. This is pretty much like a regular install, except that you’ll also use the -e command line option which means these packages will be installed in “editable” mode. + +``` +Install mpf and mpf-mc like this: + +pip install -e mpf +pip install -e mpf-mc +``` + +You should now be done, and you can verify that everyething is installed properly via: + +``` +mpf --version +``` + +Note : you could also install mpf and mpf-mc in your global environment using sudo pip3 install -e mpf and sudo pip3 install -e mpf-mc, or in your user environment using pip3 install --user -e mpf and pip3 install --user -e mpf-mc. + +## 4. Make your changes + +Be sure to add your name to the AUTHORS file in the root of the MPF or MPF-MC repo! + +## 5. Write / update unit tests + +We make heavy use of unit tests to ensure that future changes don’t break existing functionality. So write new unit tests to cover whatever you just wrote, and be sure to rerun all the unit tests to make sure your changes or additions didn’t break anything else. + +More information on creating and running MPF unit tests is here. + +## 6. Submit a pull request + +If your change fixes an open issue, reference that issue number in the comments, like “fixes #123”. diff --git a/docs/code/introduction/variables_in_code.md b/docs/code/introduction/variables_in_code.md new file mode 100644 index 0000000000..7d71b06e79 --- /dev/null +++ b/docs/code/introduction/variables_in_code.md @@ -0,0 +1,42 @@ +# Variables in Code + +## Player Variables in Code + +Player variables are only accessible when a game is running. Be prepared that the current player may change in a multiplayer game. + +Inside a (game) mode you can access the current player using `self.player`. Alternatively, you can use `self.machine.game.player` but be aware that both `self.machine.game` and `self.machine.game.player` may be None. Using the current player is probably the most common use case, but you can as well access the player variable of a specific player in code. + +You can use player variables like this: + +``` +player = self.machine.game.player # do not persist the player because it may change + # alternatively use self.player in modes + +if not player: + return # do something reasonable here but do not crash in the next line + +# read player variable +self.machine.log.info(player["my_variable"]) + +# set a variable +player["my_variable"] = 17 +``` + + + +## Machine Variables in Code + +You can use machine variables by calling into the MPF machine. + +``` +# read machine variable +self.machine.log.info(self.machine.variables.get_machine_var("my_variable")) + +# configure variable to persist to disk and expire after 1 day (optional) +# alternatively you can also use "machine_vars" in config to achieve the same +self.machine.variables.configure_machine_var("my_variable", persist=True, expire_secs=86400) + +# set a variable +self.machine.variables.set_machine_var("my_variable", 17) +``` + diff --git a/docs/config/segment_display_player.md b/docs/config/segment_display_player.md index 8607ffa659..447aa9fc64 100644 --- a/docs/config/segment_display_player.md +++ b/docs/config/segment_display_player.md @@ -96,25 +96,27 @@ Only used with the `add` action. Single value, type: `string`. Defaults to empty. Key to use with `action` `add` and `remove` to reference a text on the -segment display. +segment display. Only relevant if [segment_displays](segment_displays.md) `update_method` is `stack`, not being +used if `replace` is used. ### priority: Single value, type: int_or_token. Default: `0` Priority of this text. The segment display will maintain a stack and -show the text on top (highest priority). +show the text on top (highest priority). Only relevant if [segment_displays](segment_displays.md) `update_method` is `stack`, not being +used if `replace` is used. ### text: Single value, type: `string`. Defaults to empty. -Text to show. You can use -[Text Templates](instructions/text_templates.md). +Text to show. You can use [Text Templates](instructions/text_templates.md). +To erase the text on a display simply send an empty string "". ### transition: -Unknown type. See description below. +Note, that if you have set a duration in a show, that this duration **in**cludes the time for the incoming transition. !!! note @@ -122,9 +124,7 @@ Unknown type. See description below. the segment display or the transition effects may not be calculated and displayed properly. -### transition_out: - -Unknown type. See description below. +Example: ``` mpf-config #! segment_displays: @@ -146,6 +146,29 @@ segment_display_player: text: " *** " ``` +#### type + +The type of animation to be used. + +* push +* cover +* uncover +* split +* wipe + +#### direction + +The direction of the animation, for type `push`, `cover`, `uncover` and `wipe` value can be either `left` or `right` (default). For split the value can be `in` or `out` (default). + +#### text + +_Additonal_ text used in animation, if not set only the show text will be used. + + +### transition_out: + +Note, that if you have set a duration in a show, that this duration **ex**cludes the time for the outgoing transition. For anything else see above on the `transition` section. + There can only be one transition between text entries, so if outgoing text has a `transition_out` set, and an incoming text entry has a `transition` set, then the incoming transition will take precedence. diff --git a/docs/config/segment_displays.md b/docs/config/segment_displays.md index b832d284a6..f69471b13e 100644 --- a/docs/config/segment_displays.md +++ b/docs/config/segment_displays.md @@ -27,6 +27,8 @@ Single value, type: `string`. Defaults to empty. The number of the display. The meaning depends on the hardware platform. +* [Cobra serial segment display](../hardware/opp/cobrapin/cobrapin_serial_segment_displays.md): Not relevant, just use always `1` + ## Optional settings The following sections are optional in the `segment_displays:` section diff --git a/docs/config/show_player.md b/docs/config/show_player.md index 207bf5b6e0..2d33c89747 100644 --- a/docs/config/show_player.md +++ b/docs/config/show_player.md @@ -300,6 +300,8 @@ In the example above, the show called "show1" will be played, but the show token called "led" in the show will be replaced at runtime with the value "right_inlane". +To learn more about show tokens and how to use dynamic values take a look at the [Tokens](../shows/tokens.md) reference page. + ### speed: Single value, type: template_float_or_token. Default: `1` diff --git a/docs/game_logic/multiballs/multiball_with_traditional_ball_lock.md b/docs/game_logic/multiballs/multiball_with_traditional_ball_lock.md index 2487d8529c..42ae25b586 100644 --- a/docs/game_logic/multiballs/multiball_with_traditional_ball_lock.md +++ b/docs/game_logic/multiballs/multiball_with_traditional_ball_lock.md @@ -34,7 +34,7 @@ perspective the playfield always has only one ball in play. Perhaps the two most common types of multiballs are *virtual-only* and *physical-only*. For *virtual-only* multiballs, you only need a `multiballs:` section to your config and a corresponding *start_event*. You do not need to configure a `multiball_locks:` section. Instead, a counter or *logic_block* is often used to track when the requirements for a multiball have been satisfied, such as a certain number of shots to the captive ball target in _Metallica_ for instance. ## Setting up a physical-only multiball -In order to use a physical lock in combination witha multiball, you just define a *ball_device* as well as define a *multiball_lock* within your config files. The *ball_device* must be listed as a `lock_device` within the settings of the `multiball_lock` config section. +In order to use a physical lock in combination with a multiball, you just define a *ball_device* as well as define a *multiball_lock* within your config files. The *ball_device* must be listed as a `lock_device` within the settings of the `multiball_lock` config section. ## Making sure the right number of balls are in play diff --git a/docs/gmc/images/add_color_rect.png b/docs/gmc/images/add_color_rect.png new file mode 100644 index 0000000000..97a9f4a916 Binary files /dev/null and b/docs/gmc/images/add_color_rect.png differ diff --git a/docs/gmc/images/add_node_to_scene.png b/docs/gmc/images/add_node_to_scene.png new file mode 100644 index 0000000000..c5972fd128 Binary files /dev/null and b/docs/gmc/images/add_node_to_scene.png differ diff --git a/docs/gmc/images/create_attract_slide.png b/docs/gmc/images/create_attract_slide.png index 5a8845d596..94b7121352 100644 Binary files a/docs/gmc/images/create_attract_slide.png and b/docs/gmc/images/create_attract_slide.png differ diff --git a/docs/gmc/images/label_settings.png b/docs/gmc/images/label_settings.png new file mode 100644 index 0000000000..bedd885f13 Binary files /dev/null and b/docs/gmc/images/label_settings.png differ diff --git a/docs/gmc/images/new_scene_root_node.png b/docs/gmc/images/new_scene_root_node.png new file mode 100644 index 0000000000..990e32d5e5 Binary files /dev/null and b/docs/gmc/images/new_scene_root_node.png differ diff --git a/docs/gmc/images/new_slide_scene.png b/docs/gmc/images/new_slide_scene.png new file mode 100644 index 0000000000..f2c729f522 Binary files /dev/null and b/docs/gmc/images/new_slide_scene.png differ diff --git a/docs/gmc/images/select_rect_color.png b/docs/gmc/images/select_rect_color.png new file mode 100644 index 0000000000..a16cee6937 Binary files /dev/null and b/docs/gmc/images/select_rect_color.png differ diff --git a/docs/gmc/images/set_main_scene.png b/docs/gmc/images/set_main_scene.png new file mode 100644 index 0000000000..62f273f992 Binary files /dev/null and b/docs/gmc/images/set_main_scene.png differ diff --git a/docs/gmc/setup.md b/docs/gmc/setup.md index f0571e4046..d384df4253 100644 --- a/docs/gmc/setup.md +++ b/docs/gmc/setup.md @@ -6,6 +6,7 @@ title: Setting up GMC Before we can start building scenes, a few project setup steps are required. With your project open in the Godot Editor, go to *Project > Project Settings* to open the settings dialog. + ## Set the Main Scene Every slide, widget, and other UI file in Godot is called a "scene". When your Godot project runs, it needs to know which scene to load as its entry point. @@ -16,6 +17,9 @@ As your project becomes more complex and your knowledge of Godot improves, you m Since your Godot project is brand new, you need to tell it what scene is the entry point. On the left menu bar of Project Settings, select *Application > Run* and in the Main Scene picker, navigate to `/addons/mpf-gmc/slides/window.tscn` and select that to be your main scene. +![image](images/set_main_scene.png) + + ## Set the Window Size If you only have one display for your game, your Window size will be the size of that display. If you are using multiple displays, the Window size will be the size of the box necessary to encompass all of the displays. @@ -26,6 +30,7 @@ The other settings here will be customized later, including windowed/fullscreen You can now close the Project Settings and save your project. + ## Configure the Audio Busses Godot manages audio through a series of buses that feed into the *Master* audio bus for output to speakers. You can configure as many audio buses as you'd like, and most pinball projects use a standard set of three: *music*, *effects*, and *voice*. @@ -34,6 +39,7 @@ Godot manages audio through a series of buses that feed into the *Master* audio Each bus can be configured with its own parameters for how it plays back sounds (e.g. music plays one file at a time, voice plays files sequentially, and effects play files simultaneously), how it ducks for other buses, and which bus is the default. + ### Create Buses in Godot Editor At the bottom panel of the Godot Editor there is a tab called *Audio* which will bring up the audio control panel. By default your new project only has one bus, "Master", which is the main audio output. @@ -46,6 +52,7 @@ At the bottom panel of the Godot Editor there is a tab called *Audio* which wil Click on the *Add Bus* button to add a new bus and name it *"music"* (case sensitive). Do the same for *"effects"* and *"voice"*, or customize the buses to what you need for your project. + ### Configure the Busses in GMC Config File Unfortunately, Godot Audio Buses are not extensible like Nodes, so GMC cannot create customization options directly on the buses. Instead, a GMC configuration file will be used to configure the audio system. @@ -62,17 +69,38 @@ Create a new text file in the root of your project called *gmc.cfg* and paste in You may then adjust these defaults if you've customized your buses, but otherwise this configuration will take care of you for a while. Save the *gmc.cfg* file and close it. + ## Create an Attract Mode slide The first slide we will create is for Attract mode, so we can connect to MPF and verify that GMC is working properly. Slides can live in either a `slides` folder in the project root, or in a `slides` subfolder under any mode in your project modes folder (e.g. `/modes/attract/slides`). Create a slides folder in either location, and then in the Godot FileSystem panel right-click on the slides folder and select *Create New > Scene*. +![image](images/new_slide_scene.png) + +Enter the name of your slide "attract" as the scene name and click the tree icon to open the root type selection menu. + ![image](images/create_attract_slide.png) -Every slide in GMC must derive from the custom `MPFSlide` class, so in the *Create New Scene* dialog under **Root Type** click on the tree icon to pick a custom node class. Search for and select the `MPFSlide` class. Enter the name of your slide "attract" as the scene name, and press OK to create the scene. +Every slide in GMC must derive from the custom `MPFSlide` class, so in the *Create New Scene* dialog under **Root Type** click on the tree icon to pick a custom node class. Search for and select the `MPFSlide` class, then press "Pick". + +![image](images/new_scene_root_node.png) + +Back in the "Create new Scene" menu, press OK to complete creation. + ## Decorate the Attract slide -You'll now be at the Scene Editor view for the attract slide, which is empty. We'll start by adding a nice background color: In the *Scene* panel in the upper-left, click on the **+** icon to add a new node. In the node panel, search for and select `ColorRect` to add a colored rectangle to the scene. Drag the rectangle's corners to fill the purple dimensions on screen (which correspond to your Window size). Use the color picker in the *Inspector* panel to set a nice color. +You'll now be at the Scene Editor view for the attract slide, which is empty. We'll start by adding a nice background color: In the *Scene* panel in the upper-left, click on the **+** icon to add a new node. + +![image](images/add_node_to_scene.png) + +In the node panel, search for and select `ColorRect` to add a colored rectangle to the scene. + +![image](images/add_color_rect.png) + +Drag the rectangle's corners to fill the purple dimensions on screen (which correspond to your Window size). Use the color picker in the *Inspector* panel to set a nice color. + +![image](images/select_rect_color.png) + !!! tip @@ -82,8 +110,13 @@ Next we'll add some text to the slide. Back at the *Scene* panel, add another no In the *Inspector* panel, in the *Text* field type in the text "Welcome to GMC!", set the *Horizontal Alignment* to Center, and under *Theme Overrides > Font Sizes* set a nice big font, like 100px. +![image](images/label_settings.png) + +Overall you should have a slide with a background color and text label that looks something like this: + ![image](images/attract_slide.png) + ## Run MPF In your `attract.yaml` mode config, add the following block: @@ -110,6 +143,7 @@ In your terminal, in your project folder with your virtual environment activated sudo ln -s /Applications/Godot.app/Contents/MacOS/Godot /usr/local/bin/godot ``` + ## Create a Keymap For testing your game, it's convenient to setup a keyboard map for using keys to simulate switches and events without a connection to a physical machine. diff --git a/docs/hardware/images/O16I16_comps.jpg b/docs/hardware/images/O16I16_comps.jpg new file mode 100755 index 0000000000..53a4365409 Binary files /dev/null and b/docs/hardware/images/O16I16_comps.jpg differ diff --git a/docs/hardware/images/O32_comps.jpg b/docs/hardware/images/O32_comps.jpg new file mode 100755 index 0000000000..2852ff756b Binary files /dev/null and b/docs/hardware/images/O32_comps.jpg differ diff --git a/docs/hardware/images/fast_draw_lb.jpg b/docs/hardware/images/fast_draw_lb.jpg new file mode 100755 index 0000000000..e613371c34 Binary files /dev/null and b/docs/hardware/images/fast_draw_lb.jpg differ diff --git a/docs/hardware/images/fast_draw_pf.jpg b/docs/hardware/images/fast_draw_pf.jpg new file mode 100755 index 0000000000..d07ce31531 Binary files /dev/null and b/docs/hardware/images/fast_draw_pf.jpg differ diff --git a/docs/hardware/images/pontacq.jpg b/docs/hardware/images/pontacq.jpg new file mode 100755 index 0000000000..6d9acb0016 Binary files /dev/null and b/docs/hardware/images/pontacq.jpg differ diff --git a/docs/hardware/mypinballs/index.md b/docs/hardware/mypinballs/index.md index dc78430220..d58dc57f2a 100644 --- a/docs/hardware/mypinballs/index.md +++ b/docs/hardware/mypinballs/index.md @@ -8,10 +8,10 @@ title: MyPinballs Segment Display Controller Related Config File Sections: -* [wiring](../../config/hardware.md) -* [wiring](../../config/mypinballs.md) -* [wiring](../../config/segment_displays.md) -* [wiring](../../config/segment_display_player.md) +* [Hardware](../../config/hardware.md) +* [mypinballs](../../config/mypinballs.md) +* [segment_displays](../../config/segment_displays.md) +* [segment_display_player](../../config/segment_display_player.md) Those segment displays are controlled by a very simple serial protocol. Two variants exist: The original MyPinball controller which can controll diff --git a/docs/hardware/opp/cobrapin/cobrapin_serial_segment_displays.md b/docs/hardware/opp/cobrapin/cobrapin_serial_segment_displays.md index dcd1dba5a2..901a70fb5d 100644 --- a/docs/hardware/opp/cobrapin/cobrapin_serial_segment_displays.md +++ b/docs/hardware/opp/cobrapin/cobrapin_serial_segment_displays.md @@ -74,7 +74,7 @@ light_settings: ## Create Segment Displays Once you have the light groups defined, you can arrange them into -displays. The light group is a `neoseg_displays` object and the logical display a `segment_displays` object. You can combine multiple light groups into one logical display. In other cases you might have a 1:1 mapping between light groups and segment displays. In the latter case it might seem to overcomplicate things but this concept gives you the flexibility you might need. These are the displays that can be targeted by a segment_display_player. +displays. The light group is a `neoseg_displays` object and the logical display a [`segment_displays`](../../../config/segment_displays.md) object. The `segment_displays` object is not specific for Cobra serial segments, but being used for all kind of segment displays. You can combine multiple light groups into one logical display. In other cases you might have a 1:1 mapping between light groups and segment displays. In the latter case it might seem to overcomplicate things but this concept gives you the flexibility you might need. These are the displays that can be targeted by a segment_display_player. ``` mpf-config segment_displays: @@ -102,9 +102,11 @@ to use in the display. In some cases, the opening in your backglass may only be wide enough for 7 digits for example. In that case, change the size to 7 and the 8th digit will remain unused. -## Complete Example Config +Keep in mind that a `segment_display` is an own object regardless what `light_groups` you combine. In the above example the two groups `neoSeg_0` and `neoSeg_1` have been combined out of two 8-digit displays. Let us assume `light_group` `neoSeg_0` is used for the score of player 1 and `neoSeg_1` for the score of player 2. That would make it necessary to define two more `display_segments`, e.g. `displayScore1` and `displayScore2` which each consist of only one light group. The combined light_group could be useful if for example after the game ended you want to scroll the text "GAME OVER" from left to right along both displays (assuming they are mounted next to each other) - but is not needed if you only want to display the scores. Now assume the game is over and the final score is shown on `displayScore1` and `displayScore2`. If you now run "GAME OVER" on `neoSegTop` that is independent on the other two displays, so the scores and the text "GAME OVER" is shown at the same time (and thus unreadable since it is a logical AND connection of the texts). Which means that before you run the text "GAME OVER" you need to erase the content of `displayScore1` and `displayScore2`. In order to erase the text just send an empty String to it. -Below you find a complete example config file, with this you can use a `segment_display_player` to diplay a certain text upon a given event. +## Complete Example Config for Hardware Definition + +Below you find a complete example config file how to define your hardware. With this you can use a `segment_display_player` to diplay a certain text upon a given event. ``` mpf-config #config_version=5 @@ -189,9 +191,9 @@ light_settings: NeoSeg_green: whitepoint: [.5, .5, .5] ``` -## Complete Example Config +## Complete Example Config for Show Definition -Below you find a complete example config file to display scored points. To keep this example simple the `neoseg_displays` object is mapped 1:1 to a `segment_displays` object. +Below you find a complete example config file to display scored points. It is not using all possible hardware options like the example above, but it includes the display of a show on the LED segments. To keep this example simple the `neoseg_displays` object is mapped 1:1 to a `segment_displays` object. ``` mpf-config #config_version=5 @@ -236,3 +238,4 @@ shows: text: (txt) ``` +To learn more about show tokens and how to use dynamic values take a look [here](../../../shows/tokens.md). diff --git a/docs/hardware/opp/oppcombo/index.md b/docs/hardware/opp/oppcombo/index.md new file mode 100644 index 0000000000..f1358e4a70 --- /dev/null +++ b/docs/hardware/opp/oppcombo/index.md @@ -0,0 +1,90 @@ +--- +title: OPP EM Combo boards +--- + +# OPP EM Combo boards + +--8<-- "hardware_platform.md" + + +![image](/hardware/images/O16I16_comps.jpg) + +![image](/hardware/images/O32_comps.jpg) + +The aim of this project is to provide cheap hardware to control EM pinball machines: + +* `O16I16`: 16 soldenoid / incandescent outputs and 16 inputs combo card +* `O32`: 32 outputs soldenoid / incandescent combo card + +Firmware is currently a fork of [open-pinball-project](https://sourceforge.net/projects/open-pinball-project/) at version 2.4.0.0, [hosted at gitlab](https://gitlab.com/mrechte/open-pinball-project). + +A single BluePill MCU may control up to 32 GPIO lines, logically divided in 4 wings of 8 lines each. + +A wing is usually specialized (switch inputs, solenoids, lamps, ...) according to the hardware attached. + +This version focuses on the [blue pill plus](https://github.com/WeActStudio/BluePill-Plus) which has the advantage +of having a blue LED on PB2 which is not used by card headers. It also features an USBC-C connector. + +The size of the board is about 150 x 125 mm. + +Several boards are required to drive an EM machine. +According to the complexity and your personal taste, 3-4 to drive the play field, 2-3 to drive the light box. + +![image](/hardware/images/fast_draw_lb.jpg) + +![image](/hardware/images/fast_draw_pf.jpg) + +## Configuration + +A typical configuration will use the card serial number to identify the boeard, not the port name which may change after host reboot. +In this example, coil `c_player1_reel10` has number `0-0-0` meaning: + +`0-?-?`: driven by card id #0 + +`?-0-?`: always 0 (1 usb port only drives one MCU) + +`?-?-0`: first output (that is wing 0, pin 0) + +Coil `c_player1_reel100` is driven by the same card, second output (that is wing 0, pin 1) + + +``` mpf-config +#config_version=6 + +hardware: + platform: opp + driverboards: gen2 + +opp: + ports: /dev/ttyACM0, /dev/ttyACM1,/dev/ttyACM2, /dev/ttyACM3, /dev/ttyACM4, /dev/ttyACM5, /dev/ttyACM6 + +coils: + # Board LB_1_16O16, id #0 + c_player1_reel10: + number: 0-0-0 + default_pulse_ms: 7 + c_player1_reel100: + number: 0-0-1 + default_pulse_ms: 7 + +``` + +To set the card serial number and configure the wings, one will have to read the [interface manual](https://gitlab.com/mrechte/open-pinball-project/-/blob/master/doc/brdIntf.fodt) +and use a PC with [gen2test.py](https://gitlab.com/mrechte/open-pinball-project/-/tree/master/firmware/tools) utility. + +In the above example one would do: + +``` +./gen2test.py --serial 0 +./gen2test.py --config opp16o16icfg.py +./gen2test.py --save +``` + +## My project + +With those boards, I digitized a 1975 Gottlieb Fast Draw, which was presented to the [Pontacq Pinball Show](https://www.facebook.com/groups/154388563388625) +on June 1rst-2nd, 2024, South of France, where it ran 375 plays without any software problem. + +![image](/hardware/images/pontacq.jpg) + + diff --git a/docs/index.md b/docs/index.md index b28165ecfe..fe25e1853c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -101,6 +101,7 @@ device state, player variables, etc. * [Shows](shows/index.md) * [MPF Errors from Log Files](logs/index.md) * [Example Games](examples/index.md) + * [Extending MPF with Custom Code](code/index.md) ## Projects built on MPF diff --git a/docs/install/linux/index.md b/docs/install/linux/index.md index 568bfdbbaf..10861d4181 100644 --- a/docs/install/linux/index.md +++ b/docs/install/linux/index.md @@ -8,6 +8,10 @@ title: Installing MPF on Linux This installation guide is for MPF 0.57 and the legacy MC, which is being replaced in the upcoming MPF 0.80 with the Godot MC. If you are just getting started with MPF, we recommend you [install MPF 0.80](../index.md) instead. +## OS Preparation +In order to communicate with your pinball hardware over USB you need to add your user to the user group `dialout`. This is necessary regardless of the version of MPF (thus including the upcoming 0.80). + + ## May 2023 Update We need to update this page (we no longer suggest pipx, btw), but if you @@ -265,237 +269,3 @@ windows) for older python versions. In the case that you need a different version than the one MPF requires, it is advised to create a python virtual environment and install the required packages there, and use that virtual environment for running MPF. ---- -title: Installing MPF on Linux ---- - -# Installing MPF on Linux - - -## May 2023 Update - -We need to update this page (we no longer suggest pipx, btw), but if you -want the "real" linux install instructions, read through the GitHub -Actions job scripts in the `.github/workflows/build_wheel.yml` file. -You'll see the exact steps we use to build MPF-MC (MPF is simple to -install, it's the MC part that's tricky). Various jobs in there use -both apt-get and yum to set everything up before building the MC. - -As part of our automated build process, we build and test MPF and MPF-MC -against Ubuntu 20.04 & 22.04 and Debian Stretch & Buster. MPF 0.54 -supports Python 3.5 to 3.7. MPF 0.55 supports Python 3.6 to 3.9. MPF -0.56 supports Python 3.7 to 3.9 - -## Installing MPF Using Our Installer - -Download the MPF Debian Installer (which is used for all of these) from - - -Unzip it, and from a terminal run `chmod +x install && sudo ./install` -from the folder you unzipped the files to. If you are using a P-Roc or -P3-Roc also run `chmod +x install-proc && ./install-proc` (skip for -other platforms). Consult the README for more information. - -## Installing MPF Manually - -Current version these instructions are for v0.56.0, which is the current -"dev" branch of MPF. - -MPF 0.56 requires Python 3.7, 3.8, or 3.9. Various Linux distributions -offer to install multiple versions of Python in parallel. First check -what version of Python you might have already running on your computer. - -``` doscon -python3 --version -``` - -In some cases you might only get a Python version of 3.6, then run your -admin tool and install a higher version of python, preferably the latest -version of 3.9. If you don't want to remove the older version of Python -you can keep it in parallel, just make sure to run the installer -commands with the right version of python. If you have for example -installed Python 3.9 try to running - -``` doscon -python3.9 --version -``` - -You will need pip further down the line to complete the installation. -Same as above for Python, check what version of pip you are running and -choose the command to match the version you would like to use. Try the -following commands to figure out what pip command works for you and has -the right version. - -``` doscon -pip --version -pip3 --version -pip3.9 --version -``` - -For the rest of the chapter I will always write python3.9 and pip3.9 as -commands as reminder to use the right version, any of the above commands -might work for you (or fail). - -NOTE: If you already have an earlier version of MPF installed, uninstall -that first by using this command: - -``` doscon -sudo pip3.9 uninstall mpf-mc mpf -``` - -If you are unsure which version of MPF you have installed, you can run -this command to check what is installed: - -``` doscon -mpf --version -``` - -Updated MPF Monitor instructions (which work with pipx) are -[here](../../tools/monitor/installation.md). - -At this point, MPF 0.56.0.devXX and MPF-MC 0.56.0.devXX are installed. -(The "XX" in the version will be the dev build numbers.) - -## Download & run the "Demo Man" example game - -Now that you have MPF installed, you probably want to see it in action. -The easiest way to do that is to download a bundle of MPF examples and -run our "Demo Man" example game. To do that, follow the instructions -in the [How to run "Demo Man", an MPF example game](../../examples/demo_man.md) guide. - -There's another example project you can also check out if you want -called the "MC Demo" (for media controller demo) that lets you step -through a bunch of example display things (slides, widgets, sounds, -videos, etc). Instructions for running the MC Demo are -[here](../../examples/mc_demo.md). - -## Running MPF - -See the [How to start MPF and run your game](../../running/index.md) for details and -command-line options. - -If you see a Failed to initialize MPF exception when trying to start MPF -with Multimorphic P-ROC/P3-ROC boards with Python 3.8. - -Example Error: - -``` -Failed to initialize MPF -Traceback (most recent call last): -File “/usr/local/lib/python3.8/dist-packages/mpf/platforms/p_roc_common.py”, line 31, in - import pinproc -ModuleNotFoundError: No module named ‘pinproc’ -During handling of the above exception, another exception occurred: -Traceback (most recent call last): -File “/usr/local/lib/python3.8/dist-packages/mpf/platforms/p_roc_common.py”, line 41, in - raise ImportError -ImportError: No module named ‘pinproc’ -``` - -Try Changing [Edit install-proc:](#) - -From: - -``` -cd pypinproc -sudo python3 setup.py install -``` - -To: - -``` -cd pypinproc -python3 setup.py install --user -``` - -## Keeping MPF up-to-date - -To upgrade MPF just re-run the installer which will make sure that you -will also get updated dependencies: - -``` console -sudo ./install -``` - -If you have MPF installed via the manual procedure above, you can keep -it up-to-date by running the final two pipx commands from above which -you used to install MPF and MPF-MC. - -To install the latest dev release (not generally recommended) which -allows you to try bleeding-edge features run: - -``` console -pip3 install mpf[all] mpf-mc --pre --upgrade -``` - -To downgrade (or install a specific release x.yy.z) run: - -``` console -pip3 install mpf[all]==x.yy.z -pip3 install mpf-mc==x.yy.z -``` - -## Uninstalling MPF - -To remove MPF either because it is no longer needed or to perform a -clean install run: - -``` console -sudo pip3 uninstall mpf-mc mpf -``` - -## Specific Hardware Devices - -We got some write-ups for specific hardware platforms. They follow the -general linux installation schema but also cover some details about that -hardware. - -* [Raspberry Pi](raspberry.md) -* [Pine64](pine64.md) - -## Specific Linux Distributions - -Specifics about certain linux distributions. - -* [Xubuntu Linux](xubuntu.md) - -## What if it did not work? - -In the following we list some common problems and solutions. If you got -another problem please ask in our [forum](../../community/index.md). - -### YAML error on first start - -You will see this error if there is already a different version of -ruamel.yaml installed on your system: - -``` doscon -pkg_resources.VersionConflict: (ruamel.yaml 0.15.37 (c:\users\robert\appdata\local\programs\python\python36\lib\site-packages), Requirement.parse('ruamel.yaml<0.11,>=0.10') -``` - -This could have happened if you are upgrading to a newer version of MPF -or you have incompatible versions of MPF, MPF-MC and/or the MPF-Monitor -installed. The required ruamel.yaml version is different on newer MPF -versions. We used to install ruamel 0.11 and switched to 0.15 in MPF -0.53+. MPF cannot start with two yaml libraries. To fix this check your -versions `pip3 list` and check `mpf`, `mpf-mc` and `mpf-monitor`. Remove -the wrong version and install the right one. All versions need to match -(for instance all or all dev). - -The following command will remove all three and install the latest -release: - -``` doscon -pip3 uninstall mpf mpf-mc mpf-monitor -pip3 install mpf mpf-mc mpf-monitor -``` - -This error can also occur if you already have ruamel.yaml installed in -your python system packages for a non-MPF package. Often times, you will -have a newer version of ruamel.yaml than MPF requires. Unfortunately, -MPF cannot use a newer version of this package because that caused -issues in the past because newer versions dropped support (wheels for -windows) for older python versions. In the case that you need a -different version than the one MPF requires, it is advised to create a -python virtual environment and install the required packages there, and -use that virtual environment for running MPF. diff --git a/docs/machine_vars/index.md b/docs/machine_vars/index.md index f37fd50312..f465ff722c 100644 --- a/docs/machine_vars/index.md +++ b/docs/machine_vars/index.md @@ -37,7 +37,9 @@ display. If you want to use a machine variable in a slide player you can access it similarly to normal variables, you need to use the syntax `(machine|my_var_name)` where `my_var_name` obviously has to be replaced -with your variable name. +with your variable name. If you want to access the machine variable in a player, e.g. segment player you need to use this syntax +`{machine.my_var_name}`. In other words, when using the the first notation with the pipe symbol you access the value of the variable +as a string, in the latter case using the dot notation you access the value itself. Video about player and machine variables: diff --git a/docs/reference/index.md b/docs/reference/index.md index 8a743851de..2a633d34b4 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -18,4 +18,5 @@ looking for something specific. * [Assets](../assets/index.md) * [Shows](../shows/index.md) * [MPF Errors](../logs/index.md) -* [Example Games](../examples/index.md) \ No newline at end of file +* [Example Games](../examples/index.md) +* [Code Extensions](../code/index.md) diff --git a/docs/shows/format.md b/docs/shows/format.md index 6ac923349a..8f1f895d6b 100644 --- a/docs/shows/format.md +++ b/docs/shows/format.md @@ -75,6 +75,11 @@ Step 3: ## Setting step time +!!! warning "Important Syntax change with mpf 0.57" + + In this chapter the used sytax for the time parameter is for versions up to 0.56. With mpf 0.57 and later (incl. 0.80) + you need to add quotes around time values which are not zero, e.g. `time: "1"`, `time: "+1"` but `time: 0`. + The `time:` setting in each step represents the time when that step *starts*. The first step will always be `time: 0` diff --git a/docs/shows/tokens.md b/docs/shows/tokens.md index 2197e4fd07..6a26546d47 100644 --- a/docs/shows/tokens.md +++ b/docs/shows/tokens.md @@ -227,6 +227,56 @@ show_player: color2: blue ``` +## Using mpf variable values in tokens +In the above explainations the token values, e.g. led_02 were objects you have defined in your config file. You can as well use values of variables mpf is having, e.g. machine variables, or parameter values of an event. + +### Event parameter(argument) values + +Let's assume the following event is posted + +``` +INFO : EventManager : Event: ======'player_turn_started'====== Args={'player': , 'number': 1} +``` +The event `player_turn_started` has for example the argument `number` for the number of the player whose turn has started. + +``` mpf-config +show_player: + player_turn_started: + player_num: #The name of the show to be started upon this event + show_tokens: + txt: (number) +``` + +The number of the player whose turn started is being displayed in the show where you have used the placeholder `txt`. The argument `number` is probably used in many events. When using event arguments as tokens, just use the argument name without any prefix or dot notation. + +### Variable values +You can use as well variable values to be used in a token. For example if you want to access a player variable you can access it with `current_player.` + +``` mpf-config +show_player: + player_turn_started: + ball_num: #The name of the show to be started upon this event + show_tokens: + txt: (current_player.ball) +``` +In this example the ball number of the player is being used in your show once the player's turn has started. In case you want to access a variable of a specific player (which is not necessarily the current player) you can use `players[].` where `player_number` is the player starting with 0, e.g. the second player needs the value 1 in this example. + + +You can as well access game variables, machine variables or settings. Just use the notation `game.` or `machine.` or `settings.`. You can learn more about using variables as tokens in the [Dynamic Values](../config/instructions/dynamic_values.md) reference page. + +### Formatting of variable values +mpf is being build with Python, thus you find in some config files things which are Python specific. An example is how to tell mpf how to format the variable value. In some config files you might find something like this + +``` mpf-config +show_player: + player_turn_started: + ball_num: #The name of the show to be started upon this event + show_tokens: + txt: "{(current_player.ball):d}" +``` + +That `:d` tells mpf to format the value as a decimal. To learn about the other Python formatting options see for example here https://docs.python.org/2/library/string.html#format-specification-mini-language + ## Tokens vs Tags Almost all devices support tags. In diff --git a/includes/tutorial.md b/includes/tutorial.md index eff4236b4c..9cb7a62537 100644 --- a/includes/tutorial.md +++ b/includes/tutorial.md @@ -3,4 +3,4 @@ The guide starts [here](index.md). It's been awhile since this tutorial has been updated. If you find anything that - is no longer relevant, please let us know, or better yet, [edit or update it yourself](/about/help.md)! + is no longer relevant, please let us know, or better yet, [edit or update it yourself](https://missionpinball.org/about/help.md)! diff --git a/mkdocs.yml b/mkdocs.yml index 0e53df8b8b..adfef6b1b5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -185,6 +185,7 @@ nav: - OPP Switches: hardware/opp/switches.md - CobraPin segments: hardware/opp/cobrapin/cobrapin_serial_segment_displays.md - CobraPin Pinball Controller powered by OPP: hardware/opp/cobrapin/index.md + - OPP EM Combo boards: hardware/opp/oppcombo/index.md - P-ROC/P3-ROC: - hardware/multimorphic/index.md - Connecting: hardware/multimorphic/connecting.md @@ -1252,6 +1253,30 @@ nav: - MPF Examples Repo: examples/mpf-examples.md - Demo Man Example Game: examples/demo_man.md - MC Demo: examples/mc_demo.md + - Extending MPF with Custom Code: + - code/index.md + - Getting Started: + - code/introduction/index.md + - Machine Extensions: code/introduction/machine_code.md + - Mode Extensions: code/introduction/mode_code.md + - Variables in Code: code/introduction/variables_in_code.md + - Setup Dev Env: code/introduction/setup.md + - Debugging: code/introduction/debug.md + - API Reference: + - code/api_reference/index.md + - Core: code/api_reference/api_reference_core.md + - Devices: code/api_reference/api_reference_device.md + - Modes: code/api_reference/api_reference_modes.md + - Hardware Platforms: code/api_reference/api_reference_hardware_platforms.md + - Config Players: code/api_reference/api_reference_config_players.md + - Test: code/api_reference/api_reference_testing_class_api.md + - Miscellaneous Components: code/api_reference/api_reference_misc_components.md + - Writing Tests: + - code/Writing_Tests/index.md + - Running Tests: code/Writing_Tests/RunUnitTests.md + - Writing Tests: code/Writing_Tests/WritingCustomTestsForYourMachine.md + - BCP Interface: + - code/BCP_Protocol/index.md - Showcase: - showcase/index.md