diff --git a/docs/G-Codes.md b/docs/G-Codes.md
index 273870d56..38e7e3895 100644
--- a/docs/G-Codes.md
+++ b/docs/G-Codes.md
@@ -272,7 +272,7 @@ The following command is available when a
 [neopixel config section](Config_Reference.md#neopixel) or
 [dotstar config section](Config_Reference.md#dotstar) is enabled:
 - `SET_LED LED=<config_name> RED=<value> GREEN=<value> BLUE=<value>
-  WHITE=<value> [INDEX=<index>] [TRANSMIT=0]`: This sets the LED
+  WHITE=<value> [INDEX=<index>] [TRANSMIT=0] [SYNC=1]`: This sets the LED
   output. Each color `<value>` must be between 0.0 and 1.0. The WHITE
   option is only valid on RGBW LEDs. If multiple LED chips are
   daisy-chained then one may specify INDEX to alter the color of just
@@ -281,7 +281,12 @@ The following command is available when a
   to the provided color. If TRANSMIT=0 is specified then the color
   change will only be made on the next SET_LED command that does not
   specify TRANSMIT=0; this may be useful in combination with the INDEX
-  parameter to batch multiple updates in a daisy-chain.
+  parameter to batch multiple updates in a daisy-chain. By default, the
+  SET_LED command will sync it's changes with other ongoing gcode commands.
+  This can lead to undesirable behavior if LEDs are being set while the
+  printer is not printing as it will reset the idle timeout. If careful
+  timing is not needed, the optional SYNC=0 parameter can be specified to
+  apply the changes instantly and not reset the idle timeout.
 
 ## Servo Commands
 
diff --git a/klippy/extras/dotstar.py b/klippy/extras/dotstar.py
index 08c370fad..6c7182a2b 100644
--- a/klippy/extras/dotstar.py
+++ b/klippy/extras/dotstar.py
@@ -11,6 +11,7 @@ class PrinterDotstar:
     def __init__(self, config):
         self.printer = config.get_printer()
         name = config.get_name().split()[1]
+        self.mutex = self.printer.get_reactor().mutex()
         # Configure a software spi bus
         ppins = self.printer.lookup_object('pins')
         data_pin_params = ppins.lookup_pin(config.get('data_pin'))
@@ -26,17 +27,29 @@ class PrinterDotstar:
         red = config.getfloat('initial_RED', 0., minval=0., maxval=1.)
         green = config.getfloat('initial_GREEN', 0., minval=0., maxval=1.)
         blue = config.getfloat('initial_BLUE', 0., minval=0., maxval=1.)
-        red = int(red * 255. + .5)
-        blue = int(blue * 255. + .5)
-        green = int(green * 255. + .5)
         color_data = [0xff, blue, green, red] * self.chain_count
         self.color_data = [0, 0, 0, 0] + color_data + [0xff, 0xff, 0xff, 0xff]
-        self.printer.register_event_handler("klippy:connect", self.send_data)
+        self.update_color_data(red, green, blue)
+        self.old_color_data = bytearray([d ^ 1 for d in self.color_data])
         # Register commands
+        self.printer.register_event_handler("klippy:connect", self.send_data)
         gcode = self.printer.lookup_object('gcode')
         gcode.register_mux_command("SET_LED", "LED", name, self.cmd_SET_LED,
                                    desc=self.cmd_SET_LED_help)
+    def update_color_data(self, red, green, blue, white=None, index=None):
+        red = int(red * 255. + .5)
+        blue = int(blue * 255. + .5)
+        green = int(green * 255. + .5)
+        color_data = [0xff, blue, green, red]
+        if index is not None:
+            self.color_data[index*4:(index+1)*4] = color_data
+        else:
+            self.color_data[4:-4] = color_data * self.chain_count
     def send_data(self, print_time=None):
+        old_data, new_data = self.old_color_data, self.color_data
+        if new_data == old_data:
+            return
+
         minclock = 0
         if print_time is not None:
             minclock = self.spi.get_mcu().print_time_to_clock(print_time)
@@ -50,20 +63,25 @@ class PrinterDotstar:
         red = gcmd.get_float('RED', 0., minval=0., maxval=1.)
         green = gcmd.get_float('GREEN', 0., minval=0., maxval=1.)
         blue = gcmd.get_float('BLUE', 0., minval=0., maxval=1.)
-        transmit = gcmd.get_int('TRANSMIT', 1)
-        red = int(red * 255. + .5)
-        blue = int(blue * 255. + .5)
-        green = int(green * 255. + .5)
-        color_data = [0xff, blue, green, red]
+        white = 0.0 #dotstar's dont have white yet
         index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count)
-        if index is not None:
-            self.color_data[index*4:(index+1)*4] = color_data
-        else:
-            self.color_data[4:-4] = color_data * self.chain_count
-        # Send command
-        if transmit:
+        transmit = gcmd.get_int('TRANSMIT', 1)
+        sync = gcmd.get_int('SYNC', 1)
+        def reactor_bgfunc(print_time):
+            with self.mutex:
+                self.update_color_data(red, green, blue, index=index)
+                if transmit:
+                    self.send_data(print_time)
+        def lookahead_bgfunc(print_time):
+            reactor = self.printer.get_reactor()
+            reactor.register_callback(lambda et: reactor_bgfunc(print_time))
+        if sync:
+            #Sync LED Update with print time and send
             toolhead = self.printer.lookup_object('toolhead')
-            toolhead.register_lookahead_callback(self.send_data)
+            toolhead.register_lookahead_callback(lookahead_bgfunc)
+        else:
+            #Send update now (so as not to wake toolhead and reset idle_timeout)
+            lookahead_bgfunc(None)
 
 def load_config_prefix(config):
     return PrinterDotstar(config)
diff --git a/klippy/extras/neopixel.py b/klippy/extras/neopixel.py
index e7785d97d..1af0def44 100644
--- a/klippy/extras/neopixel.py
+++ b/klippy/extras/neopixel.py
@@ -119,6 +119,7 @@ class PrinterNeoPixel:
         white = gcmd.get_float('WHITE', 0., minval=0., maxval=1.)
         index = gcmd.get_int('INDEX', None, minval=1, maxval=self.chain_count)
         transmit = gcmd.get_int('TRANSMIT', 1)
+        sync = gcmd.get_int('SYNC', 1)
         # Update and transmit data
         def reactor_bgfunc(print_time):
             with self.mutex:
@@ -128,8 +129,13 @@ class PrinterNeoPixel:
         def lookahead_bgfunc(print_time):
             reactor = self.printer.get_reactor()
             reactor.register_callback(lambda et: reactor_bgfunc(print_time))
-        toolhead = self.printer.lookup_object('toolhead')
-        toolhead.register_lookahead_callback(lookahead_bgfunc)
+        if sync:
+            #Sync LED Update with print time and send
+            toolhead = self.printer.lookup_object('toolhead')
+            toolhead.register_lookahead_callback(lookahead_bgfunc)
+        else:
+            #Send update now (so as not to wake toolhead and reset idle_timeout)
+            lookahead_bgfunc(None)
 
 def load_config_prefix(config):
     return PrinterNeoPixel(config)