diff --git a/mpf/_version.py b/mpf/_version.py index 576dabadf..849c9d964 100644 --- a/mpf/_version.py +++ b/mpf/_version.py @@ -10,7 +10,7 @@ """ -__version__ = '0.57.0.dev22' # Also consider whether MPF-MC pyproject.toml should be updated +__version__ = '0.57.0.dev23' # Also consider whether MPF-MC pyproject.toml should be updated '''The full version of MPF.''' __short_version__ = '0.57' diff --git a/mpf/config_spec.yaml b/mpf/config_spec.yaml index eab209330..9b03fa4c9 100644 --- a/mpf/config_spec.yaml +++ b/mpf/config_spec.yaml @@ -1072,6 +1072,7 @@ mpf: platforms: ignore paths: ignore report_crashes: single|enum(ask,never,always)|ask + rgbw_white_behavior: single|enum(white_only,min_rgb,duck_rgb)|duck_rgb mpf-mc: __valid_in__: machine # todo add to validator __type__: config diff --git a/mpf/devices/light.py b/mpf/devices/light.py index 1b920c0c8..218bb80d0 100644 --- a/mpf/devices/light.py +++ b/mpf/devices/light.py @@ -57,7 +57,7 @@ class Light(SystemWideDevice, DevicePositionMixin): class_label = 'light' __slots__ = ["hw_drivers", "platforms", "delay", "default_fade_ms", "_color_correction_profile", "stack", - "_off_color", "_drivers_loaded", "_last_fade_target", "_is_rgbw"] + "_off_color", "_drivers_loaded", "_last_fade_target", "_rbgw_style"] def __init__(self, machine, name): """initialize light.""" @@ -73,7 +73,7 @@ def __init__(self, machine, name): self._color_correction_profile = None self._last_fade_target = None - self._is_rgbw = False + self._rbgw_style = None # RGBW LED will be white_only, min_rgb, duck_rgb. Others are None self.stack = list() # type: List[LightStackEntry] """A list of dicts which represents different commands that have come @@ -344,7 +344,7 @@ async def _initialize(self): ['default_fade_ms']) if len(self.hw_drivers) == 4 and all(channel in self.hw_drivers for channel in ['red', 'green', 'blue', 'white']): - self._is_rgbw = True + self._rbgw_style = self.machine.config['mpf']['rgbw_white_behavior'] self.debug_log("Initializing Light. CC Profile: %s, " "Default fade: %sms", self._color_correction_profile, @@ -616,21 +616,45 @@ def _schedule_update(self): for color, drivers in self.hw_drivers.items(): if color in ["red", "blue", "green"]: - if self._is_rgbw: # Remove the white channel from the RGB channels + if self._rbgw_style == "duck_rgb": start_brightness = (getattr(start_color, color) - min(start_color.red, start_color.green, start_color.blue)) / 255.0 target_brightness = (getattr(target_color, color) - min(target_color.red, target_color.green, target_color.blue)) / 255.0 - else: + elif self._rbgw_style == "white_only": # any shade of white is moved to the white channel + if start_color.red == start_color.green == start_color.blue: + start_brightness = 0.0 + else: + start_brightness = getattr(start_color, color) / 255.0 + if target_color.red == target_color.green == target_color.blue: + target_brightness = 0.0 + else: + target_brightness = getattr(target_color, color) / 255.0 + else: # min_rgb or None (non-RGBW) start_brightness = getattr(start_color, color) / 255.0 target_brightness = getattr(target_color, color) / 255.0 - elif color == "white": # This works to convert RGB to white and figure out the W for RGBW from RGB - start_brightness = min(start_color.red, start_color.green, start_color.blue) / 255.0 - target_brightness = min(target_color.red, target_color.green, target_color.blue) / 255.0 + + elif color == "white": + if self._rbgw_style == "white_only": + if start_color.red == start_color.green == start_color.blue: + start_brightness = start_color.red / 255.0 + else: + start_brightness = 0.0 + if target_color.red == target_color.green == target_color.blue: + target_brightness = target_color.red / 255.0 + else: + target_brightness = 0.0 + else: # white is the minimum of RGB + start_brightness = min(start_color.red, start_color.green, start_color.blue) / 255.0 + target_brightness = min(target_color.red, target_color.green, target_color.blue) / 255.0 else: raise ColorException("Invalid color {}".format(color)) + for driver in drivers: - driver.set_fade(start_brightness, start_time, target_brightness, target_time) + try: + driver.set_fade(start_brightness, start_time, target_brightness, target_time) + except UnboundLocalError: + print() for platform in self.platforms: platform.light_sync() diff --git a/mpf/tests/test_DeviceLight.py b/mpf/tests/test_DeviceLight.py index 2a3ea7f61..206bff0b8 100644 --- a/mpf/tests/test_DeviceLight.py +++ b/mpf/tests/test_DeviceLight.py @@ -385,7 +385,7 @@ def test_non_rgb_leds(self): self.assertEqual('led-4', led.hw_drivers["red"][0].number) led = self.machine.lights["led_bgr_2"] - self.assertFalse(led._is_rgbw) + self.assertFalse(led._rbgw_style) led.color(RGBColor((11, 23, 42))) self.advance_time_and_run(1) self.assertEqual(42 / 255.0, led.hw_drivers["blue"][0].current_brightness) @@ -397,7 +397,7 @@ def test_non_rgb_leds(self): # test rgbw via manual channel entries led = self.machine.lights["led3"] - self.assertTrue(led._is_rgbw) + self.assertEqual(led._rbgw_style, "duck_rgb") led.color(RGBColor((11, 23, 42))) self.advance_time_and_run(1) self.assertEqual(0 / 255.0, led.hw_drivers["red"][0].current_brightness) @@ -413,8 +413,47 @@ def test_non_rgb_leds(self): self.assertEqual(0, led.hw_drivers["blue"][0].current_brightness) self.assertEqual(1, led.hw_drivers["white"][0].current_brightness) + # test min_rgbw + led._rbgw_style = "min_rgbw" + led.color(RGBColor((11, 23, 42))) + self.advance_time_and_run(1) + self.assertEqual(11 / 255.0, led.hw_drivers["red"][0].current_brightness) + self.assertEqual(23 / 255.0, led.hw_drivers["green"][0].current_brightness) + self.assertEqual(42 / 255.0, led.hw_drivers["blue"][0].current_brightness) + self.assertEqual(11 / 255.0, led.hw_drivers["white"][0].current_brightness) + + led.color(RGBColor((255, 255, 255))) + self.advance_time_and_run(1) + self.assertEqual(1.0, led.hw_drivers["red"][0].current_brightness) + self.assertEqual(1.0, led.hw_drivers["green"][0].current_brightness) + self.assertEqual(1.0, led.hw_drivers["blue"][0].current_brightness) + self.assertEqual(1.0, led.hw_drivers["white"][0].current_brightness) + + # test rgbw white only + led._rbgw_style = "white_only" + led.color(RGBColor((11, 23, 42))) + self.advance_time_and_run(1) + self.assertEqual(11 / 255.0, led.hw_drivers["red"][0].current_brightness) + self.assertEqual(23 / 255.0, led.hw_drivers["green"][0].current_brightness) + self.assertEqual(42 / 255.0, led.hw_drivers["blue"][0].current_brightness) + self.assertEqual(0 / 255.0, led.hw_drivers["white"][0].current_brightness) + + led.color(RGBColor((255, 255, 255))) + self.advance_time_and_run(1) + self.assertEqual(0.0, led.hw_drivers["red"][0].current_brightness) + self.assertEqual(0.0, led.hw_drivers["green"][0].current_brightness) + self.assertEqual(0.0, led.hw_drivers["blue"][0].current_brightness) + self.assertEqual(1.0, led.hw_drivers["white"][0].current_brightness) + + led.color(RGBColor((100, 100, 100))) + self.advance_time_and_run(1) + self.assertEqual(0.0, led.hw_drivers["red"][0].current_brightness) + self.assertEqual(0.0, led.hw_drivers["green"][0].current_brightness) + self.assertEqual(0.0, led.hw_drivers["blue"][0].current_brightness) + self.assertEqual(100 / 255.0, led.hw_drivers["white"][0].current_brightness) + # type type: rgbw - self.assertTrue(self.machine.lights["led5"]._is_rgbw) + self.assertEqual(self.machine.lights["led5"]._rbgw_style, "duck_rgb") # test www light led = self.machine.lights["led_www"]