Repository: pwr-Solaar/Solaar

Issue:
LED feature lights/changes the color of the devices
**Information**
<!-- Make sure that your issue is not one of the known issues in the Solaar documentation at https://pwr-solaar.github.io/Solaar/ -->
<!-- Do not bother opening an issue for a version older than 1.1.8.  Upgrade to the latest version and see if your issue persists. -->
<!-- If you are not running the current version of Solaar, strongly consider upgrading to the newest version. -->
- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository): solaar 1.1.12
- Distribution: arch linux
- Kernel version (ex. `uname -srmo`): `6.8.7-arch1-2`
- Output of `solaar show`: 

<details>

```
Lightspeed Receiver
  Device path  : /dev/hidraw5
  USB id       : 046d:C547
  Serial       : 15031480
  C Pending    : ff
    Firmware   : 04.02.B0009
    Bootloader : 02.09
    Other      : 70.7E
  Has 2 paired device(s) out of a maximum of 2.
  Notifications: wireless, software present (0x000900)
  Device activity counters: 1=60

  1: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard
     Device path  : None
     WPID         : 408E
     Codename     : G915 TKL
     Kind         : keyboard
     Protocol     : HID++ 4.2
     Report Rate : 1ms
     Serial number: C7FAD1B0
     Model ID:      B35F408EC343
     Unit ID:       C7FAD1B0
                 1: BL1 12.01.B0021
                 3: 
                 0: MPK 14.02.B0022
                 3: 
                 3: 
     The power switch is located on the top right corner.
     Supports 38 HID++ 2.0 features:
         0: ROOT                   {0000} V0     
         1: FEATURE SET            {0001} V0     
         2: DEVICE FW VERSION      {0003} V4     
            Firmware: Bootloader BL1 12.01.B0021 00005E599E54
            Firmware: Other   
            Firmware: Firmware MPK 14.02.B0022 408E210DDD69
            Firmware: Other   
            Firmware: Other   
            Unit ID: C7FAD1B0  Model ID: B35F408EC343  Transport IDs: {'btleid': 'B35F', 'wpid': '408E', 'usbid': 'C343'}
         3: DEVICE NAME            {0005} V0     
            Name: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard
            Kind: keyboard
         4: WIRELESS DEVICE STATUS {1D4B} V0     
         5: CONFIG CHANGE          {0020} V0     
            Configuration: 11000000000000000000000000000000
         6: DEVICE FRIENDLY NAME   {0007} V0     
            Friendly Name: G915 TKL
         7: BATTERY VOLTAGE        {1001} V3     
            Battery: 90% 4124mV , discharging.
         8: CHANGE HOST            {1814} V1     
            Change Host        : 1:mapuo-homepad
         9: HOSTS INFO             {1815} V1     
            Host 0 (paired): mapuo-homepad
            Host 1 (unpaired): 
        10: RGB EFFECTS            {8071} V0     
            LED Control (saved): Device
            LED Control        : Device
            LEDs Logo (saved): !LEDEffectSetting {ID: 0, color: 16711680, intensity: 0, period: 100, ramp: 0, speed: 0}
            LEDs Logo        : HID++ error {'number': 1, 'request': 2796, 'error': 7, 'params': b'\x00'}
            LEDs Primary        : HID++ error {'number': 1, 'request': 2792, 'error': 7, 'params': b'\x01'}
        11: PER KEY LIGHTING V2    {8081} V2     
            Per-key Lighting (saved): {A:white, B:white, C:white, D:white, E:white, F:white, G:white, H:white, I:white, J:white, K:white, L:white, M:white, N:white, O:white, P:white, Q:white, R:white, S:white, T:white, U:white, V:white, W:white, X:white, Y:white, Z:white, 1:white, 2:white, 3:white, 4:white, 5:white, 6:white, 7:white, 8:white, 9:white, 0:white, ENTER:white, ESC:white, BACKSPACE:white, TAB:white, SPACE:white, -:white, =:white, [:white, \:white, KEY 46:white, ~:white, ;:white, ':white, `:white, ,:white, .:white, /:white, CAPS LOCK:white, F1:white, F2:white, F3:white, F4:white, F5:white, F6:white, F7:white, F8:white, F9:white, F10:white, F11:white, F12:white, PRINT:white, SCROLL LOCK:white, PASTE:white, INSERT:white, HOME:white, PAGE UP:white, DELETE:white, END:white, PAGE DOWN:white, RIGHT:white, LEFT:white, DOWN:white, UP:white, KEY 97:white, COMPOSE:white, POWER:white, KEY 100:white, KEY 101:white, KEY 102:white, KEY 103:white, LEFT CTRL:white, LEFT SHIFT:white, LEFT ALT:white, LEFT WINDOWS:white, RIGHT CTRL:white, RIGHT SHIFT:white, RIGHT ALTGR:white, RIGHT WINDOWS:white, BRIGHTNESS:white, PAUSE:white, MUTE:white, NEXT:white, PREVIOUS:white, LOGO:white}
            Per-key Lighting        : {A:white, B:white, C:white, D:white, E:white, F:white, G:white, H:white, I:white, J:white, K:white, L:white, M:white, N:white, O:white, P:white, Q:white, R:white, S:white, T:white, U:white, V:white, W:white, X:white, Y:white, Z:white, 1:white, 2:white, 3:white, 4:white, 5:white, 6:white, 7:white, 8:white, 9:white, 0:white, ENTER:white, ESC:white, BACKSPACE:white, TAB:white, SPACE:white, -:white, =:white, [:white, \:white, KEY 46:white, ~:white, ;:white, ':white, `:white, ,:white, .:white, /:white, CAPS LOCK:white, F1:white, F2:white, F3:white, F4:white, F5:white, F6:white, F7:white, F8:white, F9:white, F10:white, F11:white, F12:white, PRINT:white, SCROLL LOCK:white, PASTE:white, INSERT:white, HOME:white, PAGE UP:white, DELETE:white, END:white, PAGE DOWN:white, RIGHT:white, LEFT:white, DOWN:white, UP:white, KEY 97:white, COMPOSE:white, POWER:white, KEY 100:white, KEY 101:white, KEY 102:white, KEY 103:white, LEFT CTRL:white, LEFT SHIFT:white, LEFT ALT:white, LEFT WINDOWS:white, RIGHT CTRL:white, RIGHT SHIFT:white, RIGHT ALTGR:white, RIGHT WINDOWS:white, BRIGHTNESS:white, PAUSE:white, MUTE:white, NEXT:white, PREVIOUS:white, LOGO:white}
        12: REPROG CONTROLS V4     {1B04} V4     
            Key/Button Diversion (saved): {Host Switch Channel 1:Diverted, Host Switch Channel 2:Diverted}
            Key/Button Diversion        : {Host Switch Channel 1:Diverted, Host Switch Channel 2:Diverted}
        13: REPORT HID USAGE       {1BC0} V1     
        14: ENCRYPTION             {4100} V0     
        15: KEYBOARD DISABLE BY USAGE {4522} V0     
        16: KEYBOARD LAYOUT 2      {4540} V0     
        17: GKEY                   {8010} V0     
            Divert G and M Keys (saved): False
            Divert G and M Keys        : False
        18: MKEYS                  {8020} V0     
            M-Key LEDs (saved): {M1:False, M2:False, M3:False}
            M-Key LEDs        : {M1:False, M2:False, M3:False}
        19: MR                     {8030} V0     
            MR-Key LED (saved): False
            MR-Key LED        : False
        20: BRIGHTNESS CONTROL     {8040} V0     
            Brightness Control (saved): 50
            Brightness Control        : 50
        21: ONBOARD PROFILES       {8100} V0     
            Device Mode: On-Board
            Onboard Profiles (saved): Profile 2
            Onboard Profiles        : Profile 2
        22: REPORT RATE            {8060} V0     
            Report Rate: 1ms
            Report Rate (saved): 1ms
            Report Rate        : 1ms
        23: DFUCONTROL SIGNED      {00C2} V0     
        24: DFU                    {00D0} V3     
        25: DEVICE RESET           {1802} V0    internal, hidden 
        26: unknown:1803           {1803} V0    internal, hidden 
        27: CONFIG DEVICE PROPS    {1806} V8    internal, hidden 
        28: unknown:1813           {1813} V0    internal, hidden 
        29: OOBSTATE               {1805} V0    internal, hidden 
        30: unknown:1830           {1830} V0    internal, hidden 
        31: unknown:1890           {1890} V9    internal, hidden 
        32: unknown:1891           {1891} V9    internal, hidden 
        33: unknown:18A1           {18A1} V0    internal, hidden 
        34: unknown:1E00           {1E00} V0    hidden 
        35: unknown:1EB0           {1EB0} V0    internal, hidden 
        36: unknown:1861           {1861} V0    internal, hidden 
        37: unknown:18B0           {18B0} V0    internal, hidden 
     Has 2 reprogrammable keys:
         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1      
             divertable, persistently divertable, pos:1, group:0, group mask:empty
             reporting: diverted
         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2      
             divertable, persistently divertable, pos:2, group:0, group mask:empty
             reporting: diverted
     Battery: 90% 4124mV , discharging.

  2: G502 X PLUS
     Device path  : None
     WPID         : 4099
     Codename     : G502 X PLUS
     Kind         : mouse
     Protocol     : HID++ 4.2
     Report Rate : 1ms
     Serial number: 55E91408
     Model ID:      4099C0950000
     Unit ID:       55E91408
                 1: BL1 42.00.B0016
                 0: MPM 27.00.B0016
                 3: 
                 3: 
                 3: 
                 3: 
                 3: 
                 3: 
                 3: 
                 3: 
                 3: 
                 3: 
     Supports 32 HID++ 2.0 features:
         0: ROOT                   {0000} V0     
         1: FEATURE SET            {0001} V0     
         2: DEVICE FW VERSION      {0003} V4     
            Firmware: Bootloader BL1 42.00.B0016 AB0BFBB13A33
            Firmware: Firmware MPM 27.00.B0016 4099FBB13A33
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Firmware: Other   
            Unit ID: 55E91408  Model ID: 4099C0950000  Transport IDs: {'wpid': '4099', 'usbid': 'C095'}
         3: DEVICE NAME            {0005} V0     
            Name: G502 X PLUS
            Kind: mouse
         4: WIRELESS DEVICE STATUS {1D4B} V0     
         5: CONFIG CHANGE          {0020} V0     
            Configuration: 11000000000000000000000000000000
         6: UNIFIED BATTERY        {1004} V3     
            Battery: 95%, discharging.
         7: ADJUSTABLE DPI         {2201} V2     
            Sensitivity (DPI) (saved): 2300
            Sensitivity (DPI)        : 2300
         8: HIRES WHEEL            {2121} V0     
            Multiplier: 8
            Has invert: Normal wheel motion
            Has ratchet switch: Normal wheel mode
            Low resolution mode
            HID notification
            Scroll Wheel Direction (saved): False
            Scroll Wheel Direction        : False
            Scroll Wheel Resolution (saved): False
            Scroll Wheel Resolution        : False
            Scroll Wheel Diversion (saved): False
            Scroll Wheel Diversion        : False
         9: RGB EFFECTS            {8071} V2     
            LED Control (saved): Device
            LED Control        : Device
            LEDs Primary        : HID++ error {'number': 2, 'request': 2543, 'error': 7, 'params': b'\x00'}
        10: PER KEY LIGHTING V2    {8081} V2     
            Per-key Lighting (saved): {A:white, B:white, C:white, D:white, E:white, F:white, G:white, H:white}
            Per-key Lighting        : {A:white, B:white, C:white, D:white, E:white, F:white, G:white, H:white}
        11: ONBOARD PROFILES       {8100} V0     
            Device Mode: On-Board
            Onboard Profiles (saved): Profile 1
            Onboard Profiles        : Profile 1
        12: MOUSE BUTTON SPY       {8110} V0     
        13: REPORT RATE            {8060} V0     
            Report Rate: 1ms
            Report Rate (saved): 1ms
            Report Rate        : 1ms
        14: FORCE PAIRING          {1500} V0     
        15: DFU                    {00D0} V3     
        16: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010 
        17: unknown:1803           {1803} V0    internal, hidden, unknown:000010 
        18: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010 
        19: unknown:1811           {1811} V0    internal, hidden, unknown:000010 
        20: OOBSTATE               {1805} V0    internal, hidden 
        21: unknown:1830           {1830} V0    internal, hidden, unknown:000010 
        22: unknown:1875           {1875} V0    internal, hidden, unknown:000010 
        23: unknown:1861           {1861} V1    internal, hidden, unknown:000010 
        24: unknown:1890           {1890} V7    internal, hidden, unknown:000008 
        25: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010 
        26: unknown:1801           {1801} V0    internal, hidden, unknown:000010 
        27: unknown:1E00           {1E00} V0    hidden 
        28: unknown:1E22           {1E22} V0    internal, hidden, unknown:000010 
        29: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010 
        30: unknown:18B1           {18B1} V0    internal, hidden, unknown:000010 
        31: unknown:18C0           {18C0} V0    internal, hidden, unknown:000010 
     Battery: 95%, discharging.

```
</details>

- Contents of `~/.config/solaar/config.yaml` (or `~/.config/solaar/config.json` if `~/.config/solaar/config.yaml` not present):

<details>

```
- 1.1.12
- _NAME: MX Vertical Wireless Mouse
  _modelId: B020407BC08A
  _sensitive: {dpi: false}
  _serial: 3A83FBA3
  _unitId: 1CF35693
  _wpid: 407B
  change-host: null
  divert-keys: {82: 0, 83: 0, 86: 0, 253: 0}
  dpi: 2100
  lowres-scroll-mode: false
  lowres-smooth-scroll: false
  persistent-remappable-keys: null
  reprogrammable-keys: {80: 80, 81: 81, 82: 82, 83: 83, 86: 86, 253: 253}
- _NAME: MX Master 3 Wireless Mouse
  _modelId: B02340820000
  _sensitive: {dpi: false, smart-shift: false, thumb-scroll-invert: false}
  _serial: FB0615BE
  _unitId: FB0615BE
  _wpid: '4082'
  change-host: null
  divert-keys: {82: 0, 83: 0, 86: 0, 195: 0, 196: 0}
  dpi: 2300
  hires-scroll-mode: false
  hires-smooth-invert: false
  hires-smooth-resolution: true
  reprogrammable-keys: {80: 80, 81: 81, 82: 82, 83: 83, 86: 86, 195: 195, 196: 196}
  scroll-ratchet: 2
  smart-shift: 20
  thumb-scroll-invert: true
  thumb-scroll-mode: false
- _NAME: Wireless Mouse M185 new
  _modelId: '000000000000'
  _sensitive: {hires-scroll-mode: ignore, hires-smooth-invert: ignore, hires-smooth-resolution: ignore}
  _serial: '00000000'
  _unitId: '00000000'
  _wpid: '4054'
  divert-keys: {82: 0}
  lowres-scroll-mode: false
  pointer_speed: 256
  reprogrammable-keys: {80: 80, 81: 81, 82: 82}
- _NAME: MX Keys Keyboard
  _sensitive: {disable-keyboard-keys: false, divert-keys: false, multiplatform: false}
  _serial: 18DC7451
  _wpid: 408A
  backlight: true
  change-host: null
  disable-keyboard-keys: {1: false, 2: false, 4: false, 8: false, 16: false}
  divert-keys: {10: 0, 110: 0, 111: 0, 191: 0, 199: 0, 200: 0, 209: 0, 210: 0, 211: 0, 224: 0, 225: 0, 226: 0, 227: 0, 228: 0, 229: 0, 230: 0, 231: 0, 232: 0,
    233: 0, 234: 0, 235: 0, 236: 0}
  fn-swap: false
  multiplatform: 0
- _NAME: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard
  _absent: [hi-res-scroll, lowres-scroll-mode, hires-smooth-invert, hires-smooth-resolution, hires-scroll-mode, scroll-ratchet, smart-shift, thumb-scroll-invert,
    thumb-scroll-mode, report_rate_extended, pointer_speed, dpi, dpi_extended, speed-change, backlight, backlight_level, backlight_duration_hands_out, backlight_duration_hands_in,
    backlight_duration_powered, backlight-timed, led_control, led_zone_, fn-swap, reprogrammable-keys, persistent-remappable-keys, disable-keyboard-keys,
    crown-smooth, divert-crown, multiplatform, gesture2-gestures, gesture2-divert, gesture2-params, sidetone, equalizer, adc_power_management]
  _battery: 4097
  _modelId: B35F408EC343
  _sensitive: {divert-gkeys: true, divert-keys: false, rgb_control: false, rgb_zone_1: false, rgb_zone_2: false}
  _serial: C7FAD1B0
  _unitId: C7FAD1B0
  _wpid: 408E
  brightness_control: 50
  change-host: null
  divert-gkeys: false
  divert-keys: {209: 1, 210: 1}
  m-key-leds: {1: false, 2: false, 4: false}
  mr-key-led: false
  onboard_profiles: 2
  per-key-lighting: {1: 16777215, 2: 16777215, 3: 16777215, 4: 16777215, 5: 16777215, 6: 16777215, 7: 16777215, 8: 16777215, 9: 16777215, 10: 16777215,
    11: 16777215, 12: 16777215, 13: 16777215, 14: 16777215, 15: 16777215, 16: 16777215, 17: 16777215, 18: 16777215, 19: 16777215, 20: 16777215, 21: 16777215,
    22: 16777215, 23: 16777215, 24: 16777215, 25: 16777215, 26: 16777215, 27: 16777215, 28: 16777215, 29: 16777215, 30: 16777215, 31: 16777215, 32: 16777215,
    33: 16777215, 34: 16777215, 35: 16777215, 36: 16777215, 37: 16777215, 38: 16777215, 39: 16777215, 40: 16777215, 41: 16777215, 42: 16777215, 43: 16777215,
    44: 16777215, 45: 16777215, 46: 16777215, 47: 16777215, 48: 16777215, 49: 16777215, 50: 16777215, 51: 16777215, 52: 16777215, 53: 16777215, 54: 16777215,
    55: 16777215, 56: 16777215, 57: 16777215, 58: 16777215, 59: 16777215, 60: 16777215, 61: 16777215, 62: 16777215, 63: 16777215, 64: 16777215, 65: 16777215,
    66: 16777215, 67: 16777215, 68: 16777215, 69: 16777215, 70: 16777215, 71: 16777215, 72: 16777215, 73: 16777215, 74: 16777215, 75: 16777215, 76: 16777215,
    77: 16777215, 78: 16777215, 79: 16777215, 97: 16777215, 98: 16777215, 99: 16777215, 100: 16777215, 101: 16777215, 102: 16777215, 103: 16777215, 104: 16777215,
    105: 16777215, 106: 16777215, 107: 16777215, 108: 16777215, 109: 16777215, 110: 16777215, 111: 16777215, 153: 16777215, 155: 16777215, 156: 16777215,
    157: 16777215, 158: 16777215, 210: 16777215}
  report_rate: 1
  rgb_control: 0
  rgb_zone_2: !LEDEffectSetting {ID: 0, color: 16711680, intensity: 0, period: 100, ramp: 0, speed: 0}
- _NAME: G305 Lightspeed Wireless Gaming Mouse
  _modelId: '407400000000'
  _sensitive: {dpi: false}
  _serial: D2717600
  _unitId: 42CE6EF1
  _wpid: '4074'
  dpi: 2300
  onboard_profiles: 1
  report_rate: 1
- _NAME: G502 X PLUS
  _absent: [hi-res-scroll, lowres-scroll-mode, scroll-ratchet, smart-shift, thumb-scroll-invert, thumb-scroll-mode, report_rate_extended, pointer_speed,
    dpi_extended, speed-change, backlight, backlight_level, backlight_duration_hands_out, backlight_duration_hands_in, backlight_duration_powered, backlight-timed,
    led_control, led_zone_, brightness_control, fn-swap, reprogrammable-keys, persistent-remappable-keys, divert-keys, disable-keyboard-keys, crown-smooth,
    divert-crown, divert-gkeys, m-key-leds, mr-key-led, multiplatform, change-host, gesture2-gestures, gesture2-divert, gesture2-params, sidetone, equalizer,
    adc_power_management]
  _battery: 4100
  _modelId: 4099C0950000
  _sensitive: {dpi: true, hires-scroll-mode: true, hires-smooth-invert: true, hires-smooth-resolution: true, per-key-lighting: false, report_rate: true,
    rgb_control: true, rgb_zone_1: false}
  _serial: 55E91408
  _unitId: 55E91408
  _wpid: '4099'
  dpi: 2300
  hires-scroll-mode: false
  hires-smooth-invert: false
  hires-smooth-resolution: false
  onboard_profiles: 1
  per-key-lighting: {1: 16777215, 2: 16777215, 3: 16777215, 4: 16777215, 5: 16777215, 6: 16777215, 7: 16777215, 8: 16777215}
  report_rate: 1
  rgb_control: 0
- _NAME: Candy companion chip
  _modelId: 405F00000000
  _sensitive: {hires-scroll-mode: ignore, hires-smooth-invert: ignore, hires-smooth-resolution: ignore}
  _serial: 458E99C9
  _unitId: '32314715'
  _wpid: 405F

```
</details>


- Errors or warrnings from Solaar:
<!-- Under normal operation Solaar keeps a log of warning and error messages in ~/.tmp
while it is running as a file starting with 'Solaar'.
If this file is not available or does not have useful information you can
run Solaar as `solaar -dd`, after killing any running Solaar processes to
have Solaar log informational, warning, and error messages to stdout. -->


**Describe the bug**
A clear and concise description of what the bug is.

When Solaar is started the lights of my mouse and keyboard is turned on. They should be off as this is the way I've configured them. I don't want Solaar to control them.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to Windows Logitech G Hub and disable the lights of the mouse / set your keyboard leds and save them on board
2. Go back to Linux and Solaar will disregard all of those settings and light up the LEDs anyway

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Add any other context about the problem here.



Discussion:
Which lights are turning on?

Please provide output of `solaar -ddd` from startup until the main window appears and all devices are shown.
I think that you are referring to the per-key lighting.  There is no way to find out what the current values are so Solaar just assumes that the initial value is white.   That's probably not the best assumption.

The easiest thing for you to do is to  edit the config file, replacing 16777215 with 0.

There is also an issue with the other lights, so please still provide the output of `solaar -ddd`.
> There is no way to find out what the current values are so Solaar just assumes that the initial value is white.

Can't this option be ignored and when you explicitly configure something in Solaar the lighting control commands are sent?
Yes that is the correct solution, and will be added to Solaar.   What will actually happen is that the initial value will be a special value signalling no change.  Solaar will not write out key colors with this special value.
Just a quick thought: It shouldn't be a special value and rather a missing configuration entry, that leads to no commands being sent. This should keep compatibility with any old configuration. Solaar already contains too many checks, which shouldn't even exist and decreased by refactoring the code IMO.

Resolving patch:
diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py
--- a/lib/logitech_receiver/settings_templates.py
+++ b/lib/logitech_receiver/settings_templates.py
@@ -1646,7 +1646,7 @@ class PerKeyLighting(_Settings):
     description = _("Control per-key lighting.")
     feature = _F.PER_KEY_LIGHTING_V2
     keys_universe = _special_keys.KEYCODES
-    choices_universe = _special_keys.COLORS
+    choices_universe = _special_keys.COLORSPLUS
 
     def read(self, cached=True):
         self._pre_read(cached)
@@ -1654,29 +1654,51 @@ def read(self, cached=True):
             return self._value
         reply_map = {}
         for key in self._validator.choices:
-            reply_map[int(key)] = 0xFFFFFF  # can't read so fake a value of white
+            reply_map[int(key)] = _special_keys.COLORSPLUS["No change"]  # this signals no change
         self._value = reply_map
         return reply_map
 
     def write(self, map, save=True):
         if self._device.online:
             self.update(map, save)
-            data_bytes = b""
+            table = {}
             for key, value in map.items():
-                data_bytes += key.to_bytes(1, "big") + value.to_bytes(3, "big")
-                if len(data_bytes) >= 16:  # up to four values are packed into a request
+                if value in table:
+                    table[value].append(key)  # keys will be in order from small to large
+                else:
+                    table[value] = [key]
+            if len(table) == 1:  # use range update
+                for value, keys in table.items():  # only one, of course
+                    if value != _special_keys.COLORSPLUS["No change"]:  # this signals no change, so don't update at all
+                        data_bytes = keys[0].to_bytes(1, "big") + keys[-1].to_bytes(1, "big") + value.to_bytes(3, "big")
+                        self._device.feature_request(self.feature, 0x50, data_bytes)  # range update command to update all keys
+                        self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the changes
+            else:
+                data_bytes = b""
+                for value, keys in table.items():  # only one, of course
+                    if value != _special_keys.COLORSPLUS["No change"]:  # this signals no change, so ignore it
+                        while len(keys) > 3:  # use an optimized update command that can update up to 13 keys
+                            data = value.to_bytes(3, "big") + b"".join([key.to_bytes(1, "big") for key in keys[0:13]])
+                            self._device.feature_request(self.feature, 0x60, data)  # single-value multiple-keys update
+                            keys = keys[13:]
+                        for key in keys:
+                            data_bytes += key.to_bytes(1, "big") + value.to_bytes(3, "big")
+                            if len(data_bytes) >= 16:  # up to four values are packed into a regular update
+                                self._device.feature_request(self.feature, 0x10, data_bytes)
+                                data_bytes = b""
+                if len(data_bytes) > 0:  # update any remaining keys
                     self._device.feature_request(self.feature, 0x10, data_bytes)
-                    data_bytes = b""
-            if len(data_bytes) > 0:
-                self._device.feature_request(self.feature, 0x10, data_bytes)
-        self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the changes
+                self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the changes
         return map
 
     def write_key_value(self, key, value, save=True):
-        result = super().write_key_value(int(key), value, save)
-        if self._device.online:
-            self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the change
-        return result
+        if value != _special_keys.COLORSPLUS["No change"]:  # this signals no change
+            result = super().write_key_value(int(key), value, save)
+            if self._device.online:
+                self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the change
+            return result
+        else:
+            return True
 
     class rw_class(_FeatureRWMap):
         pass
diff --git a/lib/logitech_receiver/special_keys.py b/lib/logitech_receiver/special_keys.py
--- a/lib/logitech_receiver/special_keys.py
+++ b/lib/logitech_receiver/special_keys.py
@@ -1400,6 +1400,10 @@ def persistent_keys(action_ids):
     }
 )
 
+COLORSPLUS = _UnsortedNamedInts({"No change": -1})
+for i in COLORS:
+    COLORSPLUS[int(i)] = str(i)
+
 KEYCODES = _NamedInts(
     {
         "A": 1,


Test patch:
diff --git a/tests/logitech_receiver/test_setting_templates.py b/tests/logitech_receiver/test_setting_templates.py
--- a/tests/logitech_receiver/test_setting_templates.py
+++ b/tests/logitech_receiver/test_setting_templates.py
@@ -110,6 +110,7 @@ class FeatureTest:
     matched_calls: int = 1
     offset: int = 0x04
     version: int = 0x00
+    rewrite: bool = False
 
 
 simple_tests = [
@@ -596,12 +597,7 @@ def test_simple_template(test, mocker, mock_gethostname):
         hidpp.Response("01010300", 0x0440, "01010300"),
     ),
     Setup(
-        FeatureTest(
-            settings_templates.Gesture2Params,
-            {4: {"scale": 256}},
-            {4: {"scale": 128}},
-            2,
-        ),
+        FeatureTest(settings_templates.Gesture2Params, {4: {"scale": 256}}, {4: {"scale": 128}}, 2),
         *hidpp.responses_gestures,
         hidpp.Response("000100FF000000000000000000000000", 0x0480, "000100FF"),
         hidpp.Response("000080FF000000000000000000000000", 0x0480, "000080FF"),
@@ -615,29 +611,88 @@ def test_simple_template(test, mocker, mock_gethostname):
         hidpp.Response("E010", 0x0430, "02E010"),
         hidpp.Response("E018", 0x0430, "02E018"),
     ),
+    Setup(
+        FeatureTest(settings_templates.PerKeyLighting, {1: -1, 2: -1, 9: -1, 10: -1, 113: -1}, {2: 0xFF0000}, 4, 4, 0, 1),
+        {
+            common.NamedInt(1, "A"): special_keys.COLORSPLUS,
+            common.NamedInt(2, "B"): special_keys.COLORSPLUS,
+            common.NamedInt(9, "I"): special_keys.COLORSPLUS,
+            common.NamedInt(10, "J"): special_keys.COLORSPLUS,
+            common.NamedInt(113, "KEY 113"): special_keys.COLORSPLUS,
+        },
+        hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"),  # first group of keys
+        hidpp.Response("00000200000000000000000000000000", 0x0400, "0001"),  # second group of keys
+        hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"),  # last group of keys
+        hidpp.Response("02FF0000", 0x0410, "02FF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("02FF0000", 0x0410, "02FF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+    ),
+    Setup(
+        FeatureTest(
+            settings_templates.PerKeyLighting,
+            {1: -1, 2: -1, 9: -1, 10: -1, 113: -1},
+            {2: 0xFF0000, 9: 0xFF0000, 10: 0xFF0000},
+            8,
+            4,
+            0,
+            1,
+        ),
+        {
+            common.NamedInt(1, "A"): special_keys.COLORSPLUS,
+            common.NamedInt(2, "B"): special_keys.COLORSPLUS,
+            common.NamedInt(9, "I"): special_keys.COLORSPLUS,
+            common.NamedInt(10, "J"): special_keys.COLORSPLUS,
+            common.NamedInt(113, "KEY 113"): special_keys.COLORSPLUS,
+        },
+        hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"),  # first group of keys
+        hidpp.Response("00000200000000000000000000000000", 0x0400, "0001"),  # second group of keys
+        hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"),  # last group of keys
+        hidpp.Response("02FF0000", 0x0410, "02FF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("09FF0000", 0x0410, "09FF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("0AFF0000", 0x0410, "0AFF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("02FF000009FF00000AFF0000", 0x0410, "02FF000009FF00000AFF0000"),  # write three values
+        hidpp.Response("00", 0x0470, "00"),  # finish
+    ),
     Setup(
         FeatureTest(
             settings_templates.PerKeyLighting,
-            {1: 0xFFFFFF, 2: 0xFFFFFF, 9: 0xFFFFFF, 10: 0xFFFFFF, 113: 0xFFFFFF, 114: 0xFFFFFF},
-            {2: 0xFF0000},
-            5,
+            {1: -1, 2: -1, 9: -1, 10: -1, 113: -1, 114: -1},
+            {1: 0xFF0000, 2: 0xFF0000, 9: 0xFF0000, 10: 0xFF0000, 113: 0x00FF00, 114: 0xFF0000},
+            15,
+            4,
+            0,
+            1,
         ),
         {
-            common.NamedInt(1, "A"): special_keys.COLORS,
-            common.NamedInt(2, "B"): special_keys.COLORS,
-            common.NamedInt(9, "I"): special_keys.COLORS,
-            common.NamedInt(10, "J"): special_keys.COLORS,
-            common.NamedInt(113, "KEY 113"): special_keys.COLORS,
-            common.NamedInt(114, "KEY 114"): special_keys.COLORS,
+            common.NamedInt(1, "A"): special_keys.COLORSPLUS,
+            common.NamedInt(2, "B"): special_keys.COLORSPLUS,
+            common.NamedInt(9, "I"): special_keys.COLORSPLUS,
+            common.NamedInt(10, "J"): special_keys.COLORSPLUS,
+            common.NamedInt(113, "KEY 113"): special_keys.COLORSPLUS,
+            common.NamedInt(114, "KEY 114"): special_keys.COLORSPLUS,
         },
         hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"),  # first group of keys
         hidpp.Response("00000600000000000000000000000000", 0x0400, "0001"),  # second group of keys
         hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"),  # last group of keys
-        hidpp.Response("01FFFFFF02FFFFFF09FFFFFF0AFFFFFF", 0x0410, "01FFFFFF02FFFFFF09FFFFFF0AFFFFFF"),  # write first 4 values
-        hidpp.Response("71FFFFFF72FFFFFF", 0x0410, "71FFFFFF72FFFFFF"),  # write last two values
+        hidpp.Response("01FF0000", 0x0410, "01FF0000"),  # write one value
         hidpp.Response("00", 0x0470, "00"),  # finish
         hidpp.Response("02FF0000", 0x0410, "02FF0000"),  # write one value
         hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("09FF0000", 0x0410, "09FF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("0AFF0000", 0x0410, "0AFF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("7100FF00", 0x0410, "7100FF00"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("72FF0000", 0x0410, "72FF0000"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
+        hidpp.Response("FF00000102090A72", 0x460, "FF00000102090A72"),  # write one value for five keys
+        hidpp.Response("7100FF00", 0x0410, "7100FF00"),  # write one value
+        hidpp.Response("00", 0x0470, "00"),  # finish
     ),
     Setup(
         FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 256}, {0: 512}, 2, offset=0x9),
@@ -690,6 +745,7 @@ def test_key_template(test, mocker):
     device = hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)
     spy_request = mocker.spy(device, "request")
 
+    print("FEATURE", tst.sclass.feature)
     setting = settings_templates.check_feature(device, tst.sclass)
     assert setting is not None
     if isinstance(setting, list):
@@ -706,9 +762,13 @@ def test_key_template(test, mocker):
     write_value = setting.write(value)
     assert write_value == tst.initial_value
 
-    for key, value in tst.write_value.items():
-        write_value = setting.write_key_value(key, value)
-        assert write_value == value
+    for key, val in tst.write_value.items():
+        write_value = setting.write_key_value(key, val)
+        assert write_value == val
+        value[key] = val
+
+    if tst.rewrite:
+        write_value = setting.write(value)
 
     hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list)