From 03f3377e52ed293a3456907a8f129e0ccb23e7ee Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Sun, 8 Sep 2024 11:19:43 -0700 Subject: [PATCH 01/10] Fix missing return statement on light chain parsing --- mpf/modes/service/code/service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mpf/modes/service/code/service.py b/mpf/modes/service/code/service.py index bf503fcc5..8b8b539cb 100644 --- a/mpf/modes/service/code/service.py +++ b/mpf/modes/service/code/service.py @@ -560,6 +560,7 @@ def _generate_light_chains(self): # pylint: disable=too-many-locals return items.sort(key=lambda x: x.chain) + return items async def _volume_menu(self, platform=None): position = 0 From 9e50284f284cf7788ff463514b917e6764de9b64 Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Sun, 15 Sep 2024 12:33:25 -0700 Subject: [PATCH 02/10] Release version 0.57.3 --- mpf/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/_version.py b/mpf/_version.py index 16228f185..246104633 100644 --- a/mpf/_version.py +++ b/mpf/_version.py @@ -10,7 +10,7 @@ """ -__version__ = '0.57.3.dev1' # Also consider whether MPF-MC pyproject.toml should be updated +__version__ = '0.57.3' # Also consider whether MPF-MC pyproject.toml should be updated '''The full version of MPF.''' __short_version__ = '0.57' From 0bf5f6f58984024ab2239061b6dd9b405b1e372f Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Mon, 28 Oct 2024 18:42:08 -0700 Subject: [PATCH 03/10] Bugfix duplicate machine_vars, separate and clarify settings over BCP --- mpf/core/bcp/bcp_interface.py | 20 ++++++++++++-------- mpf/core/crash_reporter.py | 2 +- mpf/core/machine_vars.py | 8 ++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mpf/core/bcp/bcp_interface.py b/mpf/core/bcp/bcp_interface.py index 52498084b..ae940c55a 100644 --- a/mpf/core/bcp/bcp_interface.py +++ b/mpf/core/bcp/bcp_interface.py @@ -101,10 +101,10 @@ def remove_registered_trigger_event_for_client(self, client, event): if not self.machine.bcp.transport.get_transports_for_handler(event): self.machine.events.remove_handler_by_event(event=event, handler=self.bcp_trigger) - async def _bcp_receive_set_machine_var(self, client, name, value): + async def _bcp_receive_set_machine_var(self, client, name, value, persist=False): """Set machine var via bcp.""" del client - self.machine.variables.set_machine_var(name, value) + self.machine.variables.set_machine_var(name, value, persist) # document variables injected by MC '''machine_var: mc_version @@ -458,8 +458,8 @@ def _monitor_machine_vars(self, client): self.machine.register_monitor('machine_vars', self._machine_var_change) # Send initial machine variable values - for s in ("standard", "feature", "game", "coin"): - self._send_machine_vars(client, setting_type=s) + self._send_machine_vars(client) + self._send_machine_settings(client) # Establish handler for machine variable changes self.machine.bcp.transport.add_handler_to_transport("_machine_vars", client) @@ -471,10 +471,14 @@ def _monitor_machine_vars_stop(self, client): if not self.machine.bcp.transport.get_transports_for_handler("_machine_vars"): self.machine.machine_var_monitor = False - def _send_machine_vars(self, client, setting_type=None): - self.machine.bcp.transport.send_to_client( - client, bcp_command='settings', - settings=Util.convert_to_simply_type(self.machine.settings.get_settings(setting_type))) + def _send_machine_settings(self, client, setting_type=None): + settings = [setting_type] if setting_type else ["standard", "feature", "game", "coin", "hw_volume"] + for s in settings: + self.machine.bcp.transport.send_to_client( + client, bcp_command='settings', + settings=Util.convert_to_simply_type(self.machine.settings.get_settings(s))) + + def _send_machine_vars(self, client): for var_name, settings in self.machine.variables.machine_vars.items(): self.machine.bcp.transport.send_to_client(client, bcp_command='machine_variable', name=var_name, diff --git a/mpf/core/crash_reporter.py b/mpf/core/crash_reporter.py index e82786d8a..5e6fb4be5 100644 --- a/mpf/core/crash_reporter.py +++ b/mpf/core/crash_reporter.py @@ -176,7 +176,7 @@ def analyze_traceback(tb, inspection_level=None, limit=None): def _send_crash_report(report, reporting_url): - r = requests.post(reporting_url, json=report) + r = requests.post(reporting_url, json=report, timeout=60) if r.status_code != 200: print("Failed to send report. Got response code {}. Error: {}", r.status_code, r.content) else: diff --git a/mpf/core/machine_vars.py b/mpf/core/machine_vars.py index 230841ca5..88f3aba92 100644 --- a/mpf/core/machine_vars.py +++ b/mpf/core/machine_vars.py @@ -93,6 +93,11 @@ def load_machine_vars(self, machine_var_data_manager: DataManager, current_time) desc: Architecture of your machine (32bit/64bit). ''' + self.set_machine_var(name="log_file_path", value=self.machine.options.get('full_logfile_path', "")) + '''machine_var: log_file_path + + desc: Absolute path of the file log for the current running game. + ''' def __getitem__(self, key): """Allow the user to access a machine variable with []. This would be used is machine.variables["var_name"].""" @@ -177,6 +182,9 @@ def set_machine_var(self, name: str, value: Any, persist=False) -> None: ---- name: String name of the variable you're setting the value for. value: The value you're setting. This can be any Type. + persist: Whether to persist this machine var to disk. Only + applies to new/unconfigured vars; vars defined in the + machine_vars config will use their config setting. """ if name not in self.machine_vars: self.configure_machine_var(name=name, persist=persist) From 15b205396d80fb2f46d51f4837444a0c8df6a01c Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Mon, 28 Oct 2024 18:42:26 -0700 Subject: [PATCH 04/10] Include shot in shot_group hit event kwargs --- mpf/devices/shot_group.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mpf/devices/shot_group.py b/mpf/devices/shot_group.py index 1e5468d00..24d472fe9 100644 --- a/mpf/devices/shot_group.py +++ b/mpf/devices/shot_group.py @@ -47,7 +47,7 @@ def device_loaded_in_mode(self, mode: Mode, player: Player): self.rotation_pattern = deque(self.profile.config['rotation_pattern']) self.rotation_enabled = not self.config['enable_rotation_events'] for shot in self.config['shots']: - self.machine.events.add_handler("{}_hit".format(shot.name), self._hit) + self.machine.events.add_handler("{}_hit".format(shot.name), self._hit, shot=shot.name) self.machine.events.add_handler("player_shot_{}".format(shot.name), self._check_for_complete) def device_removed_from_mode(self, mode): @@ -145,7 +145,7 @@ def restart(self): for shot in self.config['shots']: shot.restart() - def _hit(self, advancing, **kwargs): + def _hit(self, advancing, shot, **kwargs): """One of the member shots in this shot group was hit. Args: @@ -157,12 +157,12 @@ def _hit(self, advancing, **kwargs): } """ del advancing - self.machine.events.post(self.name + '_hit') + self.machine.events.post(self.name + '_hit', shot=shot) '''event: (name)_hit desc: A member shots in the shot group called (name) has been hit. ''' - self.machine.events.post("{}_{}_hit".format(self.name, kwargs['state'])) + self.machine.events.post("{}_{}_hit".format(self.name, kwargs['state']), shot=shot) '''event: (name)_(state)_hit desc: A member shot with state (state) in the shot group (name) has been hit. From 34e648028d44b6dc6d123cfc202939ef7da2f6a3 Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Mon, 28 Oct 2024 18:43:11 -0700 Subject: [PATCH 05/10] Attract mode inherits from Carousel mode --- mpf/modes/attract/code/attract.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mpf/modes/attract/code/attract.py b/mpf/modes/attract/code/attract.py index 9a735b892..90973d1c5 100644 --- a/mpf/modes/attract/code/attract.py +++ b/mpf/modes/attract/code/attract.py @@ -1,9 +1,9 @@ """Contains the Attract class which is the attract mode in a pinball machine.""" -from mpf.core.mode import Mode +from mpf.modes.carousel.code.carousel import Carousel -class Attract(Mode): +class Attract(Carousel): """Default mode running in a machine when a game is not in progress. @@ -22,6 +22,13 @@ def __init__(self, *args, **kwargs): self.start_hold_time = 0.0 self.start_buttons_held = list() + def mode_init(self): + """Initialize the mode and handle missing carousel items.""" + try: + super().mode_init() + except AssertionError: + pass + def mode_start(self, **kwargs): """Start the attract mode.""" # register switch handlers for the start button press so we can @@ -50,6 +57,10 @@ def mode_start(self, **kwargs): playfield.ball_search.enable() playfield.ball_search.start() + # Check for carousel items + if self._all_items: + super().mode_start(**kwargs) + def start_button_pressed(self): """Handle start button press. From 8bb26ba125595208112ec38541ead1eb1e3f21db Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Mon, 28 Oct 2024 18:44:53 -0700 Subject: [PATCH 06/10] Improved handling of FAST Audio board --- mpf/modes/high_score/code/high_score.py | 1 + mpf/platforms/fast/fast_audio.py | 71 +++++++++++-------- .../machine_files/fast/config/audio.yaml | 8 +++ .../machine_files/fast/config/audio2.yaml | 1 + mpf/tests/test_Fast_Audio.py | 23 +++--- 5 files changed, 64 insertions(+), 40 deletions(-) diff --git a/mpf/modes/high_score/code/high_score.py b/mpf/modes/high_score/code/high_score.py index 23aa3f7bc..065f4872a 100644 --- a/mpf/modes/high_score/code/high_score.py +++ b/mpf/modes/high_score/code/high_score.py @@ -271,6 +271,7 @@ async def _ask_player_for_initials(self, player: Player, award_label: str, value input_initials = choice(unused_initials) return input_initials + # pylint: disable-msg=too-many-arguments async def _show_award_slide(self, player_num, player_name: str, category_name: str, award: str, value: int) -> None: if not self.high_score_config['award_slide_display_time']: return diff --git a/mpf/platforms/fast/fast_audio.py b/mpf/platforms/fast/fast_audio.py index 8357a048f..9834c7a04 100644 --- a/mpf/platforms/fast/fast_audio.py +++ b/mpf/platforms/fast/fast_audio.py @@ -2,6 +2,10 @@ from math import ceil from mpf.core.logging import LogMixin +from mpf.core.settings_controller import SettingEntry + +VARIABLE_NAME = "fast_audio_%s_volume" +SETTING_TYPE = "hw_volume" class FASTAudioInterface(LogMixin): @@ -17,9 +21,9 @@ def __init__(self, platform, communicator): self.machine = platform.machine self.communicator = communicator self.amps = { - 'main': {'name': 'fast_audio_main', 'label': "Speakers"}, - 'sub': {'name': 'fast_audio_sub', 'label': "Subwoofer"}, - 'headphones': {'name': 'fast_audio_headphones', 'label': "Headphones"} + 'main': {'name': 'fast_audio_main', 'label': "Speakers", 'sort': 0}, + 'sub': {'name': 'fast_audio_sub', 'label': "Subwoofer", 'sort': 1}, + 'headphones': {'name': 'fast_audio_headphones', 'label': "Headphones", 'sort': 2} } self.control_pin_pulse_times = list() @@ -35,30 +39,41 @@ def _initialize(self, **kwargs): self._register_event_handlers() def _configure_machine_vars(self): - for amp_name in self.amps: - var_name = f'fast_audio_{amp_name}_volume' - - # Is there a race condition on first boot if the linked amp - # comes in the iteration before 'main' is written? - if amp_name != 'main' and self.communicator.config[f'link_{amp_name}_to_main']: - self.machine.variables.set_machine_var( - name=var_name, - value=self.machine.variables.get_machine_var('fast_audio_main_volume'), - persist=self.communicator.config['persist_volume_settings'] - ) - elif not self.machine.variables.is_machine_var(var_name): - self.machine.variables.set_machine_var( - name=var_name, - value=self.communicator.config[f'default_{amp_name}_volume'], - persist=self.communicator.config['persist_volume_settings'] - ) + # See if main volume has been defined yet, otherwise use default + main_volume = self.machine.variables.get_machine_var('fast_audio_main_volume') + if main_volume is None: + main_volume = self.communicator.config['default_main_volume'] + + for amp_name, settings in self.amps.items(): + + default_value = self.communicator.config[f'default_{amp_name}_volume'] + if self.communicator.config.get(f'link_{amp_name}_to_main', False): + machine_var_name = VARIABLE_NAME % "main" + else: + machine_var_name = VARIABLE_NAME % amp_name + + # Create a machine variable if one doesn't exist + if not self.machine.variables.is_machine_var(machine_var_name): + self.machine.variables.set_machine_var(machine_var_name, default_value, + self.communicator.config['persist_volume_settings']) + + # Identify the machine var for this amp + settings["machine_var"] = machine_var_name + self.machine.settings.add_setting(SettingEntry( + settings['name'], + settings['label'], + settings['sort'], + machine_var_name, + default_value, + None, + SETTING_TYPE + )) def _init_amps(self): for amp_name, amp in self.amps.items(): amp['steps'] = self.communicator.config[f'{amp_name}_steps'] amp['max_volume'] = self.communicator.config[f'max_hw_volume_{amp_name}'] amp['levels_list'] = self.communicator.config[f'{amp_name}_levels_list'] - amp['link_to_main'] = self.communicator.config[f'link_{amp_name}_to_main'] # Just set everything here. The communicator will send the # config as part of its init process later @@ -71,7 +86,8 @@ def _init_amps(self): # if we have a levels list in the config, make sure the steps num is right amp['steps'] = len(amp['levels_list']) - 1 - if amp['link_to_main'] and len(amp['levels_list']) != len(self.amps['main']['levels_list']): + if self.communicator.config[f'link_{amp_name}_to_main'] and \ + len(amp['levels_list']) != len(self.amps['main']['levels_list']): raise AssertionError(f"Cannot link {amp_name} to main. The number of volume steps must be the same. " f"Main has {len(self.amps['main']['levels_list'])} steps, " f"but {amp_name} has {len(amp['levels_list'])} steps.") @@ -135,7 +151,6 @@ def send_volume_to_hw(self, amp_name=None, send_now=True): for each_amp_name in self.amps: self.send_volume_to_hw(each_amp_name, send_now) return - self.communicator.set_volume(amp_name, self.get_volume(amp_name), send_now) def _set_volume(self, amp_name, value=0, **kwargs): @@ -155,19 +170,13 @@ def _set_volume(self, amp_name, value=0, **kwargs): #self.platform.debug_log("Writing FAST amp volume %s to %s (decimal)", amp_name, value) self.send_volume_to_hw(amp_name) - if amp_name == 'main': - for other_amp_name, other_amp in self.amps.items(): - if other_amp_name != amp_name and other_amp['link_to_main']: - # Update the machine var, which will be caught and handled - self._set_machine_var_volume(other_amp_name, value) - def get_volume(self, amp_name, **kwargs): """Return the current volume of the specified amp.""" del kwargs - return self.machine.variables.get_machine_var(f'fast_audio_{amp_name}_volume') + return self.machine.variables.get_machine_var(self.amps[amp_name]["machine_var"]) or 0 def _set_machine_var_volume(self, amp_name, value): - self.machine.variables.set_machine_var(f'fast_audio_{amp_name}_volume', value) + self.machine.variables.set_machine_var(self.amps[amp_name]["machine_var"], value) def temp_volume(self, amp_name, change=1, **kwargs): """Temporarily change the volume by the specified number of units, up or down. diff --git a/mpf/tests/machine_files/fast/config/audio.yaml b/mpf/tests/machine_files/fast/config/audio.yaml index 8a1905013..2b760e46e 100644 --- a/mpf/tests/machine_files/fast/config/audio.yaml +++ b/mpf/tests/machine_files/fast/config/audio.yaml @@ -22,6 +22,14 @@ fast: power_pulse_time: 98 reset_pulse_time: 97 +machine_vars: + fast_audio_sub_volume: + initial_value: 9 + fast_audio_main_volume: + initial_value: 8 + fast_audio_headphones_volume: + initial_value: 10 + variable_player: increase_main_volume: fast_audio_main_volume: diff --git a/mpf/tests/machine_files/fast/config/audio2.yaml b/mpf/tests/machine_files/fast/config/audio2.yaml index f90f58300..f9eda074e 100644 --- a/mpf/tests/machine_files/fast/config/audio2.yaml +++ b/mpf/tests/machine_files/fast/config/audio2.yaml @@ -27,6 +27,7 @@ fast: - 14 - 15 headphones_level: line + link_sub_to_main: true machine_vars: fast_audio_main_volume: diff --git a/mpf/tests/test_Fast_Audio.py b/mpf/tests/test_Fast_Audio.py index 7350bafb6..dc4d210ca 100644 --- a/mpf/tests/test_Fast_Audio.py +++ b/mpf/tests/test_Fast_Audio.py @@ -25,10 +25,15 @@ def create_expected_commands(self): self.serial_connections['aud'].autorespond_commands['WD:3E8'] = 'WD:3E8,03' else: - self.serial_connections['aud'].expected_commands = {'AM:0B':'AM:0B', - 'AV:08':'AV:08', - 'AS:09':'AS:09', - 'AH:0A':'AH:0A',} + self.serial_connections['aud'].expected_commands = { + # 'AV:00':'AV:00', + # 'AS:00':'AS:00', + # 'AH:00':'AH:00', + 'AM:0B':'AM:0B', + 'AV:08':'AV:08', + 'AS:09':'AS:09', + 'AH:0A':'AH:0A', + } def test_audio_basics(self): @@ -69,10 +74,6 @@ def test_audio_basics(self): self.assertTrue(fast_audio.communicator.amps['sub']['enabled']) self.assertTrue(fast_audio.communicator.amps['headphones']['enabled']) - self.assertFalse(fast_audio.amps['main']['link_to_main']) - self.assertFalse(fast_audio.amps['sub']['link_to_main']) - self.assertFalse(fast_audio.amps['headphones']['link_to_main']) - # Change the volume var and make sure it's reflected in the hardware self.aud_cpu.expected_commands['AV:0D'] = 'AV:0D' self.machine.variables.set_machine_var('fast_audio_main_volume', 13) @@ -113,9 +114,13 @@ def test_control_pins(self): @test_config('audio2.yaml') def test_machine_var_loading(self): fast_audio = self.machine.default_platform.audio_interface + self.advance_time_and_run() self.assertEqual(15, self.machine.variables.get_machine_var('fast_audio_main_volume')) + self.assertEqual(15, fast_audio.get_volume('main')) self.assertEqual(15, fast_audio.communicator.amps['main']['volume']) + # sub has a machine value set in the configs, which is persisted + self.assertEqual(2, self.machine.variables.get_machine_var('fast_audio_sub_volume')) # sub is linked to main, so it will be 15 even though the config value is 2 - self.assertEqual(15, self.machine.variables.get_machine_var('fast_audio_sub_volume')) + self.assertEqual(15, fast_audio.get_volume('main')) self.assertEqual(15, fast_audio.communicator.amps['sub']['volume']) self.assertEqual(17, self.machine.variables.get_machine_var('fast_audio_headphones_volume')) From 07f957175b223836a2d80a42434634c28dc74f78 Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Tue, 29 Oct 2024 07:54:28 -0700 Subject: [PATCH 07/10] Timers: fix bug where control events pollute kwargs --- mpf/devices/timer.py | 2 +- .../modes/mode_with_timers/config/mode_with_timers.yaml | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mpf/devices/timer.py b/mpf/devices/timer.py index d8facec54..a7c70034d 100644 --- a/mpf/devices/timer.py +++ b/mpf/devices/timer.py @@ -144,8 +144,8 @@ def can_exist_outside_of_game(self): def _setup_control_events(self, event_list): self.debug_log("Setting up control events") - kwargs = {} for entry in event_list: + kwargs = {} if entry['action'] in ('add', 'subtract', 'jump', 'pause', 'set_tick_interval'): handler = getattr(self, entry['action']) kwargs = {'timer_value': entry['value']} diff --git a/mpf/tests/machine_files/timer/modes/mode_with_timers/config/mode_with_timers.yaml b/mpf/tests/machine_files/timer/modes/mode_with_timers/config/mode_with_timers.yaml index 4ada86fc9..71d255a72 100644 --- a/mpf/tests/machine_files/timer/modes/mode_with_timers/config/mode_with_timers.yaml +++ b/mpf/tests/machine_files/timer/modes/mode_with_timers/config/mode_with_timers.yaml @@ -51,6 +51,11 @@ timers: tick_interval: 1s start_running: no control_events: + # Keep this event before the reset event to catch + # a regression about the order of timer events + - event: jump_timer_up + action: jump + value: 5 - event: start_timer_up action: start - event: reset_timer_up @@ -59,9 +64,6 @@ timers: action: stop - event: restart_timer_up action: restart - - event: jump_timer_up - action: jump - value: 5 - event: jump_over_max_timer_up action: jump value: 20 From 8b1c3c10e45aae6b3f67835a675751459b6d351f Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Tue, 29 Oct 2024 08:10:14 -0700 Subject: [PATCH 08/10] Relax pylint positional args restriction --- .prospector.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.prospector.yaml b/.prospector.yaml index 9c7711c54..995f02c72 100644 --- a/.prospector.yaml +++ b/.prospector.yaml @@ -23,6 +23,7 @@ pylint: disable: - pointless-string-statement # pointless statement, which is how our event docstrings are seen - too-few-public-methods + - too-many-positional-arguments # many methods have many positional args - unsubscriptable-object # broken on python 3.9 # The following linter rules are disabled to make a refactor managable in chunks - consider-using-f-string # temporarily disabling due to the 900+ instances to be replaced From ee6caf88060a9a8fc6cd1aaa4de1435863ccb6bf Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Tue, 29 Oct 2024 08:34:04 -0700 Subject: [PATCH 09/10] Prospector fixes --- mpf/core/crash_reporter.py | 2 +- mpf/core/device_manager.py | 3 +-- mpf/core/logging.py | 9 +++++---- mpf/core/utility_functions.py | 3 +-- mpf/modes/service/code/service.py | 3 ++- mpf/platforms/fast/communicators/base.py | 3 +-- mpf/platforms/fast/fast_driver.py | 5 +++-- mpf/platforms/light_segment_displays.py | 2 +- mpf/platforms/opp/opp.py | 5 ++--- mpf/plugins/auditor.py | 2 +- 10 files changed, 18 insertions(+), 19 deletions(-) diff --git a/mpf/core/crash_reporter.py b/mpf/core/crash_reporter.py index e82786d8a..5e6fb4be5 100644 --- a/mpf/core/crash_reporter.py +++ b/mpf/core/crash_reporter.py @@ -176,7 +176,7 @@ def analyze_traceback(tb, inspection_level=None, limit=None): def _send_crash_report(report, reporting_url): - r = requests.post(reporting_url, json=report) + r = requests.post(reporting_url, json=report, timeout=60) if r.status_code != 200: print("Failed to send report. Got response code {}. Error: {}", r.status_code, r.content) else: diff --git a/mpf/core/device_manager.py b/mpf/core/device_manager.py index 6e395ee64..d30ecd58a 100644 --- a/mpf/core/device_manager.py +++ b/mpf/core/device_manager.py @@ -301,8 +301,7 @@ def __iter__(self): self.machine.log.warning("Iterating device collections directly is deprecated and will be removed. " "Access by value(): device_collections[%s] -> device_collections['%s'].values()", self.name, self.name) - for item in self.values(): - yield item + yield from self.values() def items_tagged(self, tag) -> List["Device"]: """Return of list of device objects which have a certain tag. diff --git a/mpf/core/logging.py b/mpf/core/logging.py index e71216e69..d6d77a241 100644 --- a/mpf/core/logging.py +++ b/mpf/core/logging.py @@ -160,12 +160,13 @@ def format_log_line(self, msg, context, error_no) -> str: if error_no: error_slug = "Log-{}-{}".format(self.log.name if self.log else "", error_no) error_url = log_url.format(error_slug) - if error_no and context: - return "{} Context: {} Log Code: {} ({})".format(msg, context, error_slug, error_url) + + if context: + return "{} Context: {} Log Code: {} ({})".format(msg, context, error_slug, error_url) + return "{} Log Code: {} ({})".format(msg, error_slug, error_url) + if context: return "{} Context: {} ".format(msg, context) - if error_no: - return "{} Log Code: {} ({})".format(msg, error_slug, error_url) return msg diff --git a/mpf/core/utility_functions.py b/mpf/core/utility_functions.py index 01a1651ff..691216d93 100644 --- a/mpf/core/utility_functions.py +++ b/mpf/core/utility_functions.py @@ -185,8 +185,7 @@ def flatten_list(incoming_list): """Convert a list of nested lists and/or values into a single one-dimensional list.""" for item in incoming_list: if isinstance(item, IterableCollection) and not isinstance(item, str): - for inner_item in Util.flatten_list(item): - yield inner_item + yield from Util.flatten_list(item) else: yield item diff --git a/mpf/modes/service/code/service.py b/mpf/modes/service/code/service.py index 8b8b539cb..b67135670 100644 --- a/mpf/modes/service/code/service.py +++ b/mpf/modes/service/code/service.py @@ -508,6 +508,7 @@ def _generate_light_chains(self): # pylint: disable=too-many-locals for board, l in items: numbers = l.get_hw_numbers() chain_2 = None + addr_2 = None # Just choose the first one as representative? number = numbers[0] if "-" in number: @@ -557,7 +558,7 @@ def _generate_light_chains(self): # pylint: disable=too-many-locals items.append(LightChainMap(platform_name, chain_name, chain)) # do not crash if no lights are configured if not items: # pragma: no cover - return + return [] items.sort(key=lambda x: x.chain) return items diff --git a/mpf/platforms/fast/communicators/base.py b/mpf/platforms/fast/communicators/base.py index 6fa0e69a9..743f5eefe 100644 --- a/mpf/platforms/fast/communicators/base.py +++ b/mpf/platforms/fast/communicators/base.py @@ -448,9 +448,9 @@ async def _socket_writer(self): if self.pause_sending_flag.is_set(): await self.pause_sending_flag.wait() + # TODO better way to catch shutting down? except SerialException as e: self.log.error(e) - return # TODO better way to catch shutting down? def write_to_port(self, msg, log_msg=None): """Send a message as is, without encoding or adding a character.""" @@ -464,4 +464,3 @@ def write_to_port(self, msg, log_msg=None): self.writer.write(msg) except AttributeError: self.log.warning("Serial connection is not open. Cannot send message: %s", msg) - return diff --git a/mpf/platforms/fast/fast_driver.py b/mpf/platforms/fast/fast_driver.py index 8a2c0a982..d4a04ea9f 100644 --- a/mpf/platforms/fast/fast_driver.py +++ b/mpf/platforms/fast/fast_driver.py @@ -503,6 +503,9 @@ def _pulse(self, pulse_settings: PulseSettings, hold_settings: HoldSettings = No reconfigured = True if hold_settings is not None: + hold_power = Util.float_to_pwm8_hex_string(hold_settings.power) + hold_ms = "00" + if hold_settings.duration > 25500: raise AssertionError("FAST platform does not support hold durations > 25500ms") if 25500 >= hold_settings.duration > 255: @@ -512,8 +515,6 @@ def _pulse(self, pulse_settings: PulseSettings, hold_settings: HoldSettings = No hold_ms = Util.int_to_hex_string(hold_settings.duration) mode = '10' - hold_power = Util.float_to_pwm8_hex_string(hold_settings.power) - else: hold_ms = self.current_driver_config.param3 hold_power = self.current_driver_config.param4 diff --git a/mpf/platforms/light_segment_displays.py b/mpf/platforms/light_segment_displays.py index 922ec6583..7d761e0ec 100644 --- a/mpf/platforms/light_segment_displays.py +++ b/mpf/platforms/light_segment_displays.py @@ -2,7 +2,7 @@ import logging from mpf.devices.segment_display.segment_display_text import ColoredSegmentDisplayText -from mpf.core.segment_mappings import SEVEN_SEGMENTS, BCD_SEGMENTS, FOURTEEN_SEGMENTS, SIXTEEN_SEGMENTS,\ +from mpf.core.segment_mappings import SEVEN_SEGMENTS, BCD_SEGMENTS, FOURTEEN_SEGMENTS, SIXTEEN_SEGMENTS, \ EIGHT_SEGMENTS, TextToSegmentMapper from mpf.platforms.interfaces.segment_display_platform_interface import SegmentDisplaySoftwareFlashPlatformInterface from mpf.core.platform import SegmentDisplaySoftwareFlashPlatform diff --git a/mpf/platforms/opp/opp.py b/mpf/platforms/opp/opp.py index 63fd06fc6..60d0f18c4 100644 --- a/mpf/platforms/opp/opp.py +++ b/mpf/platforms/opp/opp.py @@ -890,7 +890,6 @@ def parse_light_number_to_channels(self, number: str, subtype: str): ] self.raise_config_error("Unknown subtype {}".format(subtype), 8) - return [] def configure_light(self, number, subtype, config, platform_settings): """Configure a led or matrix light.""" @@ -949,7 +948,6 @@ def configure_light(self, number, subtype, config, platform_settings): return self.opp_incands[index].configure_software_fade_incand(light_num) self.raise_config_error("Unknown subtype {}".format(subtype), 12) - return None async def _poll_sender(self, chain_serial): """Poll switches.""" @@ -1148,6 +1146,7 @@ async def configure_servo(self, number, config: dict) -> OPPServo: """Generate an OPPServo class with the given number.""" del config chain_serial, _, pin_number = number.split('-') # Unused value is 'card' + possible_inputs = None if self.min_version[chain_serial] < 0x02020002: self.raise_config_error("Servos not supported on this OPP FW version: {}.".format( @@ -1157,7 +1156,7 @@ async def configure_servo(self, number, config: dict) -> OPPServo: if inputs.chain_serial == chain_serial: possible_inputs = self._get_numbers(inputs.mask) - if 8 <= int(pin_number) < 16 and int(pin_number) in possible_inputs: + if 8 <= int(pin_number) < 16 and possible_inputs and int(pin_number) in possible_inputs: servo_number = int(pin_number) - 8 else: self.raise_config_error("Servo unavailable at this number: {}.".format(number), 24) diff --git a/mpf/plugins/auditor.py b/mpf/plugins/auditor.py index 2af146933..c803312c6 100644 --- a/mpf/plugins/auditor.py +++ b/mpf/plugins/auditor.py @@ -78,7 +78,7 @@ def _load_defaults(self): self.switchnames_to_audit = { # Don't audit tagged switches, or credit switches during free play - x.name for x in self.machine.switches.values() if \ + x.name for x in self.machine.switches.values() if ('no_audit' not in x.tags) and ('no_audit_free' not in x.tags or not is_free_play) } From 758f5beb36b75acb22e0a7c1706156d16fee54f5 Mon Sep 17 00:00:00 2001 From: Anthony van Winkle Date: Tue, 29 Oct 2024 08:46:54 -0700 Subject: [PATCH 10/10] Increment dev version 0.57.4.dev1 --- mpf/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/_version.py b/mpf/_version.py index 246104633..453e8a485 100644 --- a/mpf/_version.py +++ b/mpf/_version.py @@ -10,7 +10,7 @@ """ -__version__ = '0.57.3' # Also consider whether MPF-MC pyproject.toml should be updated +__version__ = '0.57.4.dev1' # Also consider whether MPF-MC pyproject.toml should be updated '''The full version of MPF.''' __short_version__ = '0.57'