From 082f6a27dece8d1883751d3f2af1c2b0f0b6802c Mon Sep 17 00:00:00 2001
From: InsanityAutomation
 <38436470+InsanityAutomation@users.noreply.github.com>
Date: Sat, 12 Jan 2019 01:41:48 -0500
Subject: [PATCH] ADAPTIVE_FAN_SLOWING extension to hotend thermal protection
 (#12853)

---
 Marlin/Configuration_adv.h                    |   2 +
 Marlin/src/Marlin.cpp                         |  15 +--
 Marlin/src/Marlin.h                           |  18 ---
 Marlin/src/config/default/Configuration_adv.h |   2 +
 .../AlephObjects/TAZ4/Configuration_adv.h     |   2 +
 .../examples/Anet/A2/Configuration_adv.h      |   2 +
 .../examples/Anet/A2plus/Configuration_adv.h  |   2 +
 .../examples/Anet/A6/Configuration_adv.h      |   2 +
 .../examples/Anet/A8/Configuration_adv.h      |   2 +
 .../config/examples/ArmEd/Configuration_adv.h |   2 +
 .../BIBO/TouchX/cyclops/Configuration_adv.h   |   2 +
 .../BIBO/TouchX/default/Configuration_adv.h   |   2 +
 .../examples/BQ/Hephestos/Configuration_adv.h |   2 +
 .../BQ/Hephestos_2/Configuration_adv.h        |   2 +
 .../examples/BQ/WITBOX/Configuration_adv.h    |   2 +
 .../examples/Cartesio/Configuration_adv.h     |   2 +
 .../Creality/CR-10/Configuration_adv.h        |   2 +
 .../Creality/CR-10S/Configuration_adv.h       |   2 +
 .../Creality/CR-10mini/Configuration_adv.h    |   2 +
 .../Creality/CR-8/Configuration_adv.h         |   2 +
 .../Creality/Ender-2/Configuration_adv.h      |   2 +
 .../Creality/Ender-3/Configuration_adv.h      |   2 +
 .../Creality/Ender-4/Configuration_adv.h      |   2 +
 .../examples/Einstart-S/Configuration_adv.h   |   2 +
 .../config/examples/Felix/Configuration_adv.h |   2 +
 .../FolgerTech/i3-2020/Configuration_adv.h    |   2 +
 .../Formbot/Raptor/Configuration_adv.h        |   2 +
 .../Formbot/T_Rex_2+/Configuration_adv.h      |   2 +
 .../Formbot/T_Rex_3/Configuration_adv.h       |   2 +
 .../Geeetech/MeCreator2/Configuration_adv.h   |   2 +
 .../Prusa i3 Pro C/Configuration_adv.h        |   2 +
 .../Prusa i3 Pro W/Configuration_adv.h        |   2 +
 .../Infitary/i3-M508/Configuration_adv.h      |   2 +
 .../examples/JGAurora/A5/Configuration_adv.h  |   2 +
 .../examples/MakerParts/Configuration_adv.h   |   2 +
 .../examples/Malyan/M150/Configuration_adv.h  |   2 +
 .../examples/Malyan/M200/Configuration_adv.h  |   2 +
 .../Micromake/C1/enhanced/Configuration_adv.h |   2 +
 .../examples/Mks/Robin/Configuration_adv.h    |   2 +
 .../examples/Mks/Sbase/Configuration_adv.h    |   2 +
 .../examples/RigidBot/Configuration_adv.h     |   2 +
 .../config/examples/SCARA/Configuration_adv.h |   2 +
 .../examples/Sanguinololu/Configuration_adv.h |   2 +
 .../examples/TheBorg/Configuration_adv.h      |   2 +
 .../examples/TinyBoy2/Configuration_adv.h     |   2 +
 .../examples/Tronxy/X3A/Configuration_adv.h   |   2 +
 .../UltiMachine/Archim1/Configuration_adv.h   |   2 +
 .../UltiMachine/Archim2/Configuration_adv.h   |   2 +
 .../examples/VORONDesign/Configuration_adv.h  |   2 +
 .../config/examples/VORONDesign/_Bootscreen.h |   2 +-
 .../Velleman/K8200/Configuration_adv.h        |   2 +
 .../Velleman/K8400/Configuration_adv.h        |   2 +
 .../Wanhao/Duplicator 6/Configuration_adv.h   |   2 +
 .../delta/Anycubic/Kossel/Configuration_adv.h |   2 +
 .../FLSUN/auto_calibrate/Configuration_adv.h  |   2 +
 .../delta/FLSUN/kossel/Configuration_adv.h    |   2 +
 .../FLSUN/kossel_mini/Configuration_adv.h     |   2 +
 .../Geeetech/Rostock 301/Configuration_adv.h  |   2 +
 .../delta/MKS/SBASE/Configuration_adv.h       |   2 +
 .../Tevo Little Monster/Configuration_adv.h   |   2 +
 .../delta/generic/Configuration_adv.h         |   2 +
 .../delta/kossel_mini/Configuration_adv.h     |   2 +
 .../delta/kossel_xl/Configuration_adv.h       |   2 +
 .../gCreate/gMax1.5+/Configuration_adv.h      |   2 +
 .../examples/makibox/Configuration_adv.h      |   2 +
 .../tvrrug/Round2/Configuration_adv.h         |   2 +
 .../config/examples/wt150/Configuration_adv.h |   2 +
 Marlin/src/feature/power.cpp                  |   2 +-
 Marlin/src/feature/power_loss_recovery.cpp    |   2 +-
 Marlin/src/gcode/control/M42.cpp              |  10 +-
 Marlin/src/gcode/control/M80_M81.cpp          |   6 +-
 Marlin/src/gcode/temperature/M106_M107.cpp    |  52 ++------
 Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp   |  18 +--
 Marlin/src/lcd/dogm/status_screen_DOGM.cpp    |  19 ++-
 .../lcd/dogm/status_screen_lite_ST7920.cpp    |  15 ++-
 Marlin/src/lcd/extensible_ui/ui_api.cpp       |  12 +-
 Marlin/src/lcd/extensible_ui/ui_api.h         |   5 +-
 Marlin/src/lcd/malyanlcd.cpp                  |   2 +-
 Marlin/src/lcd/menu/menu_main.cpp             |   2 +-
 Marlin/src/lcd/menu/menu_temperature.cpp      |  22 ++--
 Marlin/src/lcd/menu/menu_tune.cpp             |  16 +--
 Marlin/src/module/planner.cpp                 |   8 +-
 Marlin/src/module/probe.cpp                   |  20 +--
 Marlin/src/module/probe.h                     |   4 -
 Marlin/src/module/temperature.cpp             | 117 +++++++++++++++++-
 Marlin/src/module/temperature.h               |  65 ++++++++++
 Marlin/src/module/tool_change.cpp             |   4 +-
 buildroot/share/tests/LPC1768_tests           |   2 +-
 88 files changed, 405 insertions(+), 161 deletions(-)

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 6d47a3b71a1..25ec655a4d1 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/Marlin.cpp b/Marlin/src/Marlin.cpp
index 4792f243805..72e59c3e45e 100644
--- a/Marlin/src/Marlin.cpp
+++ b/Marlin/src/Marlin.cpp
@@ -164,17 +164,6 @@ bool Running = true;
   TempUnit input_temp_units = TEMPUNIT_C;
 #endif
 
-#if FAN_COUNT > 0
-  uint8_t fan_speed[FAN_COUNT] = { 0 };
-  #if ENABLED(EXTRA_FAN_SPEED)
-    uint8_t old_fan_speed[FAN_COUNT], new_fan_speed[FAN_COUNT];
-  #endif
-  #if ENABLED(PROBING_FANS_OFF)
-    bool fans_paused; // = false;
-    uint8_t paused_fan_speed[FAN_COUNT] = { 0 };
-  #endif
-#endif
-
 // For M109 and M190, this flag may be cleared (by M108) to exit the wait loop
 volatile bool wait_for_heatup = true;
 
@@ -655,7 +644,7 @@ void stop() {
   print_job_timer.stop();
 
   #if ENABLED(PROBING_FANS_OFF)
-    if (fans_paused) fans_pause(false); // put things back the way they were
+    if (thermalManager.fans_paused) thermalManager.set_fans_paused(false); // put things back the way they were
   #endif
 
   if (IsRunning()) {
@@ -976,7 +965,7 @@ void loop() {
         quickstop_stepper();
         print_job_timer.stop();
         thermalManager.disable_all_heaters();
-        zero_fan_speeds();
+        thermalManager.zero_fan_speeds();
         wait_for_heatup = false;
         #if ENABLED(POWER_LOSS_RECOVERY)
           card.removeJobRecoveryFile();
diff --git a/Marlin/src/Marlin.h b/Marlin/src/Marlin.h
index 1ccac95e52c..9b66460c62c 100644
--- a/Marlin/src/Marlin.h
+++ b/Marlin/src/Marlin.h
@@ -81,24 +81,6 @@ extern volatile bool wait_for_heatup;
 // Inactivity shutdown timer
 extern millis_t max_inactive_time, stepper_inactive_time;
 
-#if FAN_COUNT > 0
-  extern uint8_t fan_speed[FAN_COUNT];
-  #if ENABLED(EXTRA_FAN_SPEED)
-    extern uint8_t old_fan_speed[FAN_COUNT], new_fan_speed[FAN_COUNT];
-  #endif
-  #if ENABLED(PROBING_FANS_OFF)
-    extern bool fans_paused;
-    extern uint8_t paused_fan_speed[FAN_COUNT];
-  #endif
-  #define FANS_LOOP(I) LOOP_L_N(I, FAN_COUNT)
-#endif
-
-inline void zero_fan_speeds() {
-  #if FAN_COUNT > 0
-    FANS_LOOP(i) fan_speed[i] = 0;
-  #endif
-}
-
 #if ENABLED(USE_CONTROLLER_FAN)
   extern uint8_t controllerfan_speed;
 #endif
diff --git a/Marlin/src/config/default/Configuration_adv.h b/Marlin/src/config/default/Configuration_adv.h
index 6d47a3b71a1..25ec655a4d1 100755
--- a/Marlin/src/config/default/Configuration_adv.h
+++ b/Marlin/src/config/default/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h b/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
index 78517285e5f..a505ca9b00e 100644
--- a/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
+++ b/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Anet/A2/Configuration_adv.h b/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
index 65c7085cbab..5efa35f32bd 100644
--- a/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h b/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
index 65c7085cbab..5efa35f32bd 100644
--- a/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Anet/A6/Configuration_adv.h b/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
index c35759bfcc5..52291cde114 100644
--- a/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 10    // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Anet/A8/Configuration_adv.h b/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
index 99a22b0aa4d..50413ec6fa2 100644
--- a/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 10    // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/ArmEd/Configuration_adv.h b/Marlin/src/config/examples/ArmEd/Configuration_adv.h
index bc634b2b00a..f6eb65317e5 100644
--- a/Marlin/src/config/examples/ArmEd/Configuration_adv.h
+++ b/Marlin/src/config/examples/ArmEd/Configuration_adv.h
@@ -81,6 +81,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h b/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
index d64b0bf6d96..3ca6432c7bd 100644
--- a/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
+++ b/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 45        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 2     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h b/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
index d0990b4a988..04012fcdf29 100644
--- a/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
+++ b/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 2     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h b/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
index b3bbbc26145..4088fb51081 100644
--- a/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h b/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
index 26602d8f479..ddf0e28a6ca 100644
--- a/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h b/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
index b3bbbc26145..4088fb51081 100644
--- a/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Cartesio/Configuration_adv.h b/Marlin/src/config/examples/Cartesio/Configuration_adv.h
index 6386dbe2415..0be82a99d0a 100644
--- a/Marlin/src/config/examples/Cartesio/Configuration_adv.h
+++ b/Marlin/src/config/examples/Cartesio/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
index 2a95e6d06a2..42c09888881 100755
--- a/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
index f9f05638522..c3599eb7085 100644
--- a/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
index bd2366c3f70..0b2df5ace37 100644
--- a/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
index 5ce2d658845..ab94bb3720d 100644
--- a/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
index 6b869936c84..6d8ad819d28 100644
--- a/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
index c7244e7b141..9f4783d3e4c 100644
--- a/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
index 4c6bfb9f45b..15e7538704c 100644
--- a/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Einstart-S/Configuration_adv.h b/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
index 326b365e650..8e723b5c050 100644
--- a/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
+++ b/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Felix/Configuration_adv.h b/Marlin/src/config/examples/Felix/Configuration_adv.h
index ded7b602e00..1aa306536e0 100644
--- a/Marlin/src/config/examples/Felix/Configuration_adv.h
+++ b/Marlin/src/config/examples/Felix/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h b/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
index 9256e45f8f0..ec6eb7bc21d 100644
--- a/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
+++ b/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 2     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h b/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
index 47cf2f9af5b..7f9d6307176 100644
--- a/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 210       // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 2     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h b/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
index 3c6358d66cf..306d4c9cc06 100644
--- a/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 10    // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h b/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
index 7f9cac028e3..3e771dfdc20 100644
--- a/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 10    // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h
index 7ae209c2f17..e34e378537d 100644
--- a/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h
index 5a16712c91e..d66c99e7d0c 100644
--- a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h	
+++ b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h	
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h
index 5a16712c91e..d66c99e7d0c 100644
--- a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h	
+++ b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h	
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h b/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
index 84210667671..43918b0e07b 100644
--- a/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
+++ b/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h b/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
index 3cceb01ea27..7c0222bb565 100644
--- a/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
+++ b/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/MakerParts/Configuration_adv.h b/Marlin/src/config/examples/MakerParts/Configuration_adv.h
index ea2cea1a278..85beaa8fb65 100644
--- a/Marlin/src/config/examples/MakerParts/Configuration_adv.h
+++ b/Marlin/src/config/examples/MakerParts/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h b/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
index 209978a40c9..6ab3697cbe1 100644
--- a/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
+++ b/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h b/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
index 28ad8c8bc44..ca7c5ca7c54 100644
--- a/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
+++ b/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h b/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
index cea080ffab4..0ff5f76a224 100644
--- a/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
+++ b/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Mks/Robin/Configuration_adv.h b/Marlin/src/config/examples/Mks/Robin/Configuration_adv.h
index 10f6d5819f3..01207d3abae 100644
--- a/Marlin/src/config/examples/Mks/Robin/Configuration_adv.h
+++ b/Marlin/src/config/examples/Mks/Robin/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h b/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
index 3492ff5257f..393edceb46b 100644
--- a/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
+++ b/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 50        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 6     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/RigidBot/Configuration_adv.h b/Marlin/src/config/examples/RigidBot/Configuration_adv.h
index be28001a3f8..de062d7e3ce 100644
--- a/Marlin/src/config/examples/RigidBot/Configuration_adv.h
+++ b/Marlin/src/config/examples/RigidBot/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/SCARA/Configuration_adv.h b/Marlin/src/config/examples/SCARA/Configuration_adv.h
index 2eba90b99d6..dcca0eadca2 100644
--- a/Marlin/src/config/examples/SCARA/Configuration_adv.h
+++ b/Marlin/src/config/examples/SCARA/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h b/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
index eae71de535a..4c1e4ea174a 100644
--- a/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
+++ b/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/TheBorg/Configuration_adv.h b/Marlin/src/config/examples/TheBorg/Configuration_adv.h
index 3e62ac095b1..b5ec4b6b847 100644
--- a/Marlin/src/config/examples/TheBorg/Configuration_adv.h
+++ b/Marlin/src/config/examples/TheBorg/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 50        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 6     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h b/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
index 5243eb78b33..7a54b52c506 100644
--- a/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
+++ b/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h b/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
index 05dc421289d..cb59d0144cf 100644
--- a/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
+++ b/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/UltiMachine/Archim1/Configuration_adv.h b/Marlin/src/config/examples/UltiMachine/Archim1/Configuration_adv.h
index 09ffd0d6f00..a8ebcd0ce07 100644
--- a/Marlin/src/config/examples/UltiMachine/Archim1/Configuration_adv.h
+++ b/Marlin/src/config/examples/UltiMachine/Archim1/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h b/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
index 6bd5580f9a5..11079889527 100644
--- a/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
+++ b/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/VORONDesign/Configuration_adv.h b/Marlin/src/config/examples/VORONDesign/Configuration_adv.h
index 79a1f1545a9..2613067a004 100644
--- a/Marlin/src/config/examples/VORONDesign/Configuration_adv.h
+++ b/Marlin/src/config/examples/VORONDesign/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/VORONDesign/_Bootscreen.h b/Marlin/src/config/examples/VORONDesign/_Bootscreen.h
index bce4b0d4c44..13e777f0329 100644
--- a/Marlin/src/config/examples/VORONDesign/_Bootscreen.h
+++ b/Marlin/src/config/examples/VORONDesign/_Bootscreen.h
@@ -77,5 +77,5 @@ const unsigned char custom_start_bmp[] PROGMEM = {
   B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
   B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
   B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
-  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000 
+  B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000
 };
diff --git a/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h b/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
index 3a306399063..ab4865d4cb4 100644
--- a/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
+++ b/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
@@ -87,6 +87,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 8     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h b/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
index 665eb525557..5cbde84ec12 100644
--- a/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
+++ b/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h b/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h
index 5682109d8e4..b94637a1b20 100644
--- a/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h	
+++ b/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h	
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h b/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
index 5cb5add8b30..7633d4e2665 100644
--- a/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
index 051df3dd331..c9926bcb655 100644
--- a/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
index 051df3dd331..c9926bcb655 100644
--- a/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
index eae4151cd60..d36ea2ec4fa 100644
--- a/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/Geeetech/Rostock 301/Configuration_adv.h b/Marlin/src/config/examples/delta/Geeetech/Rostock 301/Configuration_adv.h
index f2c7f9aa7a0..7fd887b45a1 100644
--- a/Marlin/src/config/examples/delta/Geeetech/Rostock 301/Configuration_adv.h	
+++ b/Marlin/src/config/examples/delta/Geeetech/Rostock 301/Configuration_adv.h	
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/MKS/SBASE/Configuration_adv.h b/Marlin/src/config/examples/delta/MKS/SBASE/Configuration_adv.h
index c537f9ca0c9..4d20314228f 100644
--- a/Marlin/src/config/examples/delta/MKS/SBASE/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/MKS/SBASE/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 50        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 6     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/Tevo Little Monster/Configuration_adv.h b/Marlin/src/config/examples/delta/Tevo Little Monster/Configuration_adv.h
index 70070b11c90..4a6179d2a8f 100644
--- a/Marlin/src/config/examples/delta/Tevo Little Monster/Configuration_adv.h	
+++ b/Marlin/src/config/examples/delta/Tevo Little Monster/Configuration_adv.h	
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 60        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 10     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/generic/Configuration_adv.h b/Marlin/src/config/examples/delta/generic/Configuration_adv.h
index eae4151cd60..d36ea2ec4fa 100644
--- a/Marlin/src/config/examples/delta/generic/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/generic/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h b/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
index eae4151cd60..d36ea2ec4fa 100644
--- a/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h b/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
index 3504f662fda..ef13bc32111 100644
--- a/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
index 301ffacd51e..5c45b876e16 100644
--- a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
+++ b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 50        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 3     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/makibox/Configuration_adv.h b/Marlin/src/config/examples/makibox/Configuration_adv.h
index 69b84b2579b..e1b192b1cba 100644
--- a/Marlin/src/config/examples/makibox/Configuration_adv.h
+++ b/Marlin/src/config/examples/makibox/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h b/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
index ff6dd2f4231..d4cb2606cc6 100644
--- a/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
+++ b/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/config/examples/wt150/Configuration_adv.h b/Marlin/src/config/examples/wt150/Configuration_adv.h
index 57e3e714f36..52b99e69299 100644
--- a/Marlin/src/config/examples/wt150/Configuration_adv.h
+++ b/Marlin/src/config/examples/wt150/Configuration_adv.h
@@ -77,6 +77,8 @@
   #define THERMAL_PROTECTION_PERIOD 40        // Seconds
   #define THERMAL_PROTECTION_HYSTERESIS 4     // Degrees Celsius
 
+  //#define ADAPTIVE_FAN_SLOWING              // Slow part cooling fan if temperature drops
+
   /**
    * Whenever an M104, M109, or M303 increases the target temperature, the
    * firmware will wait for the WATCH_TEMP_PERIOD to expire. If the temperature
diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp
index 892166ba1a5..53741358168 100644
--- a/Marlin/src/feature/power.cpp
+++ b/Marlin/src/feature/power.cpp
@@ -39,7 +39,7 @@ millis_t Power::lastPowerOn;
 
 bool Power::is_power_needed() {
   #if ENABLED(AUTO_POWER_FANS)
-    FANS_LOOP(i) if (fan_speed[i]) return true;
+    FANS_LOOP(i) if (thermalManager.fan_speed[i]) return true;
   #endif
 
   #if ENABLED(AUTO_POWER_E_FANS)
diff --git a/Marlin/src/feature/power_loss_recovery.cpp b/Marlin/src/feature/power_loss_recovery.cpp
index 6de329051db..a53829ef06b 100644
--- a/Marlin/src/feature/power_loss_recovery.cpp
+++ b/Marlin/src/feature/power_loss_recovery.cpp
@@ -162,7 +162,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const bool save_queue/*=
     #endif
 
     #if FAN_COUNT
-      COPY(info.fan_speed, fan_speed);
+      COPY(info.fan_speed, thermalManager.fan_speed);
     #endif
 
     #if HAS_LEVELING
diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp
index 2a7323a8617..efd6b0ef038 100644
--- a/Marlin/src/gcode/control/M42.cpp
+++ b/Marlin/src/gcode/control/M42.cpp
@@ -24,6 +24,10 @@
 #include "../../Marlin.h" // for pin_is_protected
 #include "../../inc/MarlinConfig.h"
 
+#if FAN_COUNT > 0
+  #include "../../module/temperature.h"
+#endif
+
 /**
  * M42: Change pin status via GCode
  *
@@ -52,13 +56,13 @@ void GcodeSuite::M42() {
   #if FAN_COUNT > 0
     switch (pin) {
       #if HAS_FAN0
-        case FAN_PIN: fan_speed[0] = pin_status; break;
+        case FAN_PIN: thermalManager.fan_speed[0] = pin_status; break;
       #endif
       #if HAS_FAN1
-        case FAN1_PIN: fan_speed[1] = pin_status; break;
+        case FAN1_PIN: thermalManager.fan_speed[1] = pin_status; break;
       #endif
       #if HAS_FAN2
-        case FAN2_PIN: fan_speed[2] = pin_status; break;
+        case FAN2_PIN: thermalManager.fan_speed[2] = pin_status; break;
       #endif
     }
   #endif
diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp
index 3dbf15a794c..b4a7b81d8dc 100644
--- a/Marlin/src/gcode/control/M80_M81.cpp
+++ b/Marlin/src/gcode/control/M80_M81.cpp
@@ -100,10 +100,10 @@ void GcodeSuite::M81() {
   planner.finish_and_disable();
 
   #if FAN_COUNT > 0
-    zero_fan_speeds();
+    thermalManager.zero_fan_speeds();
     #if ENABLED(PROBING_FANS_OFF)
-      fans_paused = false;
-      ZERO(paused_fan_speed);
+      thermalManager.fans_paused = false;
+      ZERO(thermalManager.paused_fan_speed);
     #endif
   #endif
 
diff --git a/Marlin/src/gcode/temperature/M106_M107.cpp b/Marlin/src/gcode/temperature/M106_M107.cpp
index 5fcf465e708..8b9daa779c9 100644
--- a/Marlin/src/gcode/temperature/M106_M107.cpp
+++ b/Marlin/src/gcode/temperature/M106_M107.cpp
@@ -25,13 +25,9 @@
 #if FAN_COUNT > 0
 
 #include "../gcode.h"
-#include "../../Marlin.h" // for fan_speed
-
 #include "../../module/motion.h"
+#include "../../module/temperature.h"
 
-#if ENABLED(SINGLENOZZLE)
-  #include "../../module/tool_change.h"
-#endif
 
 /**
  * M106: Set Fan Speed
@@ -50,39 +46,16 @@ void GcodeSuite::M106() {
   const uint8_t p = parser.byteval('P', MIN(active_extruder, FAN_COUNT - 1));
 
   if (p < MIN(EXTRUDERS, FAN_COUNT)) {
-    uint16_t s = parser.ushortval('S', 255);
-    NOMORE(s, 255U);
-
-    uint8_t np = p;
-
-    #if ENABLED(SINGLENOZZLE)
-      if (p != active_extruder) {
-        if (p < EXTRUDERS) singlenozzle_fan_speed[p] = s;
-        return;
-      }
-      np = 0; // Always use fan index 0 with SINGLENOZZLE
-    #endif
 
     #if ENABLED(EXTRA_FAN_SPEED)
       const int16_t t = parser.intval('T');
-      if (t > 0) {
-        switch (t) {
-          case 1:
-            fan_speed[np] = old_fan_speed[np];
-            break;
-          case 2:
-            old_fan_speed[np] = fan_speed[np];
-            fan_speed[np] = new_fan_speed[np];
-            break;
-          default:
-            new_fan_speed[np] = MIN(t, 255U);
-            break;
-        }
-        return;
-      }
-    #endif // EXTRA_FAN_SPEED
+      if (t > 0) return thermalManager.set_temp_fan_speed(p, t);
+    #endif
 
-    fan_speed[np] = s;
+    uint16_t s = parser.ushortval('S', 255);
+    NOMORE(s, 255U);
+
+    thermalManager.set_fan_speed(p, s);
   }
 }
 
@@ -90,16 +63,7 @@ void GcodeSuite::M106() {
  * M107: Fan Off
  */
 void GcodeSuite::M107() {
-  const uint16_t p = parser.byteval('P', active_extruder);
-
-  #if ENABLED(SINGLENOZZLE)
-    if (p != active_extruder) {
-      if (p < EXTRUDERS) singlenozzle_fan_speed[p] = 0;
-      return;
-    }
-  #endif
-
-  if (p < MIN(EXTRUDERS, FAN_COUNT)) fan_speed[p] = 0;
+  thermalManager.set_fan_speed(parser.byteval('P', active_extruder), 0);
 }
 
 #endif // FAN_COUNT > 0
diff --git a/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp b/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
index c309500b137..e9f552f8806 100644
--- a/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
+++ b/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
@@ -866,11 +866,15 @@ void MarlinUI::draw_status_screen() {
           _draw_print_progress();
         #else
           char c;
-          int per;
+          uint16_t per;
           #if HAS_FAN0
-            if (blink) {
-              c = 'F';
-              per = ((int(fan_speed[0]) + 1) * 100) / 256;
+            if (blink || thermalManager.fan_speed_scaler[0] < 128) {
+              uint16_t spd = thermalManager.fan_speed[0];
+              if (blink) c = 'F';
+              #if ENABLED(ADAPTIVE_FAN_SLOWING)
+                else { c = '*'; spd = (spd * thermalManager.fan_speed_scaler[0]) >> 7; }
+              #endif
+              per = thermalManager.fanPercent(spd);
             }
             else
           #endif
@@ -1049,13 +1053,13 @@ void MarlinUI::draw_status_screen() {
       #if FAN_COUNT > 0
         if (0
           #if HAS_FAN0
-            || fan_speed[0]
+            || thermalManager.fan_speed[0]
           #endif
           #if HAS_FAN1
-            || fan_speed[1]
+            || thermalManager.fan_speed[1]
           #endif
           #if HAS_FAN2
-            || fan_speed[2]
+            || thermalManager.fan_speed[2]
           #endif
         ) leds |= LED_C;
       #endif // FAN_COUNT > 0
diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
index 4f044c0b2f6..b265e6d6cb2 100644
--- a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
+++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
@@ -291,7 +291,7 @@ void MarlinUI::draw_status_screen() {
       static uint8_t fan_frame;
       if (old_blink != blink) {
         old_blink = blink;
-        if (!fan_speed[0] || ++fan_frame >= STATUS_FAN_FRAMES) fan_frame = 0;
+        if (!thermalManager.fan_speed[0] || ++fan_frame >= STATUS_FAN_FRAMES) fan_frame = 0;
       }
     #endif
     if (PAGE_CONTAINS(STATUS_FAN_Y, STATUS_FAN_Y + STATUS_FAN_HEIGHT - 1))
@@ -305,7 +305,7 @@ void MarlinUI::draw_status_screen() {
             fan_frame == 3 ? status_fan3_bmp :
           #endif
         #elif STATUS_FAN_FRAMES > 1
-          blink && fan_speed[0] ? status_fan1_bmp :
+          blink && thermalManager.fan_speed[0] ? status_fan1_bmp :
         #endif
         status_fan0_bmp
       );
@@ -328,11 +328,18 @@ void MarlinUI::draw_status_screen() {
     // Fan, if a bitmap was provided
     #if DO_DRAW_FAN
       if (PAGE_CONTAINS(STATUS_FAN_TEXT_Y - INFO_FONT_ASCENT, STATUS_FAN_TEXT_Y - 1)) {
-        const int per = ((int(fan_speed[0]) + 1) * 100) / 256;
-        if (per) {
+        char c = '%';
+        uint16_t spd = thermalManager.fan_speed[0];
+        if (spd) {
+          #if ENABLED(ADAPTIVE_FAN_SLOWING)
+            if (!blink && thermalManager.fan_speed_scaler[0] < 128) {
+              spd = (spd * thermalManager.fan_speed_scaler[0]) >> 7;
+              c = '*';
+            }
+          #endif
           lcd_moveto(STATUS_FAN_TEXT_X, STATUS_FAN_TEXT_Y);
-          lcd_put_u8str(itostr3(per));
-          lcd_put_wchar('%');
+          lcd_put_u8str(itostr3(thermalManager.fanPercent(spd)));
+          lcd_put_wchar(c);
         }
       }
     #endif
diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
index 126ef00b51e..af7cc433e12 100644
--- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
+++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
@@ -707,7 +707,7 @@ bool ST7920_Lite_Status_Screen::indicators_changed() {
   // them only during blinks we gain a bit of stability.
   const bool       blink             = ui.get_blink();
   const uint16_t   feedrate_perc     = feedrate_percentage;
-  const uint8_t    fs                = (((uint16_t)fan_speed[0] + 1) * 100) / 256;
+  const uint16_t   fs                = (thermalManager.fan_speed[0] * uint16_t(thermalManager.fan_speed_scaler[0])) >> 7;
   const int16_t    extruder_1_target = thermalManager.degTargetHotend(0);
   #if HOTENDS > 1
     const int16_t  extruder_2_target = thermalManager.degTargetHotend(1);
@@ -734,7 +734,6 @@ void ST7920_Lite_Status_Screen::update_indicators(const bool forceUpdate) {
     const bool       blink             = ui.get_blink();
     const duration_t elapsed           = print_job_timer.duration();
     const uint16_t   feedrate_perc     = feedrate_percentage;
-    const uint8_t    fs                = (((uint16_t)fan_speed[0] + 1) * 100) / 256;
     const int16_t    extruder_1_temp   = thermalManager.degHotend(0),
                      extruder_1_target = thermalManager.degTargetHotend(0);
     #if HOTENDS > 1
@@ -753,12 +752,20 @@ void ST7920_Lite_Status_Screen::update_indicators(const bool forceUpdate) {
     #if HAS_HEATED_BED
       draw_bed_temp(bed_temp, bed_target, forceUpdate);
     #endif
-    draw_fan_speed(fs);
+
+    uint16_t spd = thermalManager.fan_speed[0];
+
+    #if ENABLED(ADAPTIVE_FAN_SLOWING)
+      if (!blink && thermalManager.fan_speed_scaler[0] < 128)
+        spd = (spd * thermalManager.fan_speed_scaler[0]) >> 7;
+    #endif
+
+    draw_fan_speed(thermalManager.fanPercent(spd));
     draw_print_time(elapsed);
     draw_feedrate_percentage(feedrate_perc);
 
     // Update the fan and bed animations
-    if (fs) draw_fan_icon(blink);
+    if (spd) draw_fan_icon(blink);
     #if HAS_HEATED_BED
       draw_heat_icon(bed_target > 0 && blink, bed_target > 0);
     #endif
diff --git a/Marlin/src/lcd/extensible_ui/ui_api.cpp b/Marlin/src/lcd/extensible_ui/ui_api.cpp
index 75f9464a09c..f5a13012666 100644
--- a/Marlin/src/lcd/extensible_ui/ui_api.cpp
+++ b/Marlin/src/lcd/extensible_ui/ui_api.cpp
@@ -180,7 +180,13 @@ namespace ExtUI {
     return thermalManager.degTargetHotend(extruder - E0);
   }
 
-  float getFan_percent(const fan_t fan) { return ((float(fan_speed[fan - FAN0]) + 1) * 100) / 256; }
+  float getTargetFan_percent(const fan_t fan) {
+    return thermalManager.fanPercent(thermalManager.fan_speed[fan - FAN0]);
+  }
+
+  float getActualFan_percent(const fan_t fan) {
+    return thermalManager.fanPercent((thermalManager.fan_speed[fan - FAN0] * uint16_t(thermalManager.fan_speed_scaler[fan - FAN0])) >> 7);
+  }
 
   float getAxisPosition_mm(const axis_t axis) {
     return flags.manual_motion ? destination[axis] : current_position[axis];
@@ -560,9 +566,9 @@ namespace ExtUI {
     thermalManager.setTargetHotend(clamp(value, 0, heater_maxtemp[e] - 15), e);
   }
 
-  void setFan_percent(float value, const fan_t fan) {
+  void setTargetFan_percent(const float value, const fan_t fan) {
     if (fan < FAN_COUNT)
-      fan_speed[fan - FAN0] = clamp(round(value * 255 / 100), 0, 255);
+      thermalManager.set_fan_speed(fan - FAN0, map(value, 0, 100, 0, 255));
   }
 
   void setFeedrate_percent(const float value) {
diff --git a/Marlin/src/lcd/extensible_ui/ui_api.h b/Marlin/src/lcd/extensible_ui/ui_api.h
index 1a86680a1ff..9a61ef75be2 100644
--- a/Marlin/src/lcd/extensible_ui/ui_api.h
+++ b/Marlin/src/lcd/extensible_ui/ui_api.h
@@ -72,7 +72,8 @@ namespace ExtUI {
   float getActualTemp_celsius(const extruder_t);
   float getTargetTemp_celsius(const heater_t);
   float getTargetTemp_celsius(const extruder_t);
-  float getFan_percent(const fan_t);
+  float getTargetFan_percent(const fan_t);
+  float getActualFan_percent(const fan_t);
   float getAxisPosition_mm(const axis_t);
   float getAxisPosition_mm(const extruder_t);
   float getAxisSteps_per_mm(const axis_t);
@@ -100,7 +101,7 @@ namespace ExtUI {
 
   void setTargetTemp_celsius(const float, const heater_t);
   void setTargetTemp_celsius(const float, const extruder_t);
-  void setFan_percent(const float, const fan_t);
+  void setTargetFan_percent(const float, const fan_t);
   void setAxisPosition_mm(const float, const axis_t);
   void setAxisPosition_mm(const float, const extruder_t);
   void setAxisSteps_per_mm(const float, const axis_t);
diff --git a/Marlin/src/lcd/malyanlcd.cpp b/Marlin/src/lcd/malyanlcd.cpp
index a88fa62ca62..ece49465182 100644
--- a/Marlin/src/lcd/malyanlcd.cpp
+++ b/Marlin/src/lcd/malyanlcd.cpp
@@ -255,7 +255,7 @@ void process_lcd_p_command(const char* command) {
         quickstop_stepper();
         print_job_timer.stop();
         thermalManager.disable_all_heaters();
-        zero_fan_speeds();
+        thermalManager.zero_fan_speeds();
         wait_for_heatup = false;
         write_to_lcd_P(PSTR("{SYS:STARTED}"));
       #endif
diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp
index 30dd6c333d9..4e419d84ab1 100644
--- a/Marlin/src/lcd/menu/menu_main.cpp
+++ b/Marlin/src/lcd/menu/menu_main.cpp
@@ -54,7 +54,7 @@ void lcd_pause() {
 void lcd_resume() {
   #if ENABLED(SDSUPPORT)
     if (card.isPaused()) enqueue_and_echo_commands_P(PSTR("M24"));
-  #elif ENABLED(ACTION_ON_RESUME)
+  #elif defined(ACTION_ON_RESUME)
     SERIAL_ECHOLNPGM("//action:" ACTION_ON_RESUME);
   #endif
 }
diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp
index e0d559025e3..571e1e25725 100644
--- a/Marlin/src/lcd/menu/menu_temperature.cpp
+++ b/Marlin/src/lcd/menu/menu_temperature.cpp
@@ -52,9 +52,9 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb
   #endif
   #if FAN_COUNT > 0
     #if FAN_COUNT > 1
-      fan_speed[active_extruder < FAN_COUNT ? active_extruder : 0] = fan;
+      thermalManager.set_fan_speed(active_extruder < FAN_COUNT ? active_extruder : 0, fan);
     #else
-      fan_speed[0] = fan;
+      thermalManager.set_fan_speed(0, fan);
     #endif
   #else
     UNUSED(fan);
@@ -292,7 +292,7 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb
   }
 
   void lcd_cooldown() {
-    zero_fan_speeds();
+    thermalManager.zero_fan_speeds();
     thermalManager.disable_all_heaters();
     ui.return_to_status();
   }
@@ -339,21 +339,21 @@ void menu_temperature() {
   //
   #if FAN_COUNT > 0
     #if HAS_FAN0
-      MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &fan_speed[0], 0, 255);
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &thermalManager.lcd_tmpfan_speed[0], 0, 255, thermalManager.lcd_setFanSpeed0);
       #if ENABLED(EXTRA_FAN_SPEED)
-        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &new_fan_speed[0], 3, 255);
+        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &thermalManager.new_fan_speed[0], 3, 255);
       #endif
     #endif
-    #if HAS_FAN1
-      MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 2", &fan_speed[1], 0, 255);
+    #if HAS_FAN1 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 1)
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int8, MSG_FAN_SPEED " 2", &thermalManager.lcd_tmpfan_speed[1], 0, 255, thermalManager.lcd_setFanSpeed1);
       #if ENABLED(EXTRA_FAN_SPEED)
-        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &new_fan_speed[1], 3, 255);
+        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &thermalManager.new_fan_speed[1], 3, 255);
       #endif
     #endif
-    #if HAS_FAN2
-      MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 3", &fan_speed[2], 0, 255);
+    #if HAS_FAN2 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 2)
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int8, MSG_FAN_SPEED " 3", &thermalManager.lcd_tmpfan_speed[2], 0, 255, thermalManager.lcd_setFanSpeed2);
       #if ENABLED(EXTRA_FAN_SPEED)
-        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &new_fan_speed[2], 3, 255);
+        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &thermalManager.new_fan_speed[2], 3, 255);
       #endif
     #endif
   #endif // FAN_COUNT > 0
diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp
index b3e41fa5d0a..4eb05b55f43 100644
--- a/Marlin/src/lcd/menu/menu_tune.cpp
+++ b/Marlin/src/lcd/menu/menu_tune.cpp
@@ -141,21 +141,21 @@ void menu_tune() {
   //
   #if FAN_COUNT > 0
     #if HAS_FAN0
-      MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &fan_speed[0], 0, 255);
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &thermalManager.lcd_tmpfan_speed[0], 0, 255, thermalManager.lcd_setFanSpeed0);
       #if ENABLED(EXTRA_FAN_SPEED)
-        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &new_fan_speed[0], 3, 255);
+        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &thermalManager.new_fan_speed[0], 3, 255);
       #endif
     #endif
-    #if HAS_FAN1
-      MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 2", &fan_speed[1], 0, 255);
+    #if HAS_FAN1 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 1)
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int8, MSG_FAN_SPEED " 2", &thermalManager.lcd_tmpfan_speed[1], 0, 255, thermalManager.lcd_setFanSpeed1);
       #if ENABLED(EXTRA_FAN_SPEED)
-        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &new_fan_speed[1], 3, 255);
+        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &thermalManager.new_fan_speed[1], 3, 255);
       #endif
     #endif
-    #if HAS_FAN2
-      MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 3", &fan_speed[2], 0, 255);
+    #if HAS_FAN2 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 2)
+      MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int8, MSG_FAN_SPEED " 3", &thermalManager.lcd_tmpfan_speed[2], 0, 255, thermalManager.lcd_setFanSpeed2);
       #if ENABLED(EXTRA_FAN_SPEED)
-        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &new_fan_speed[2], 3, 255);
+        MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &thermalManager.new_fan_speed[2], 3, 255);
       #endif
     #endif
   #endif // FAN_COUNT > 0
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index 523cfcaf945..056817c8ddc 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -1178,10 +1178,9 @@ void Planner::check_axes_activity() {
   #endif
 
   if (has_blocks_queued()) {
-
     #if FAN_COUNT > 0
       FANS_LOOP(i)
-        tail_fan_speed[i] = block_buffer[block_buffer_tail].fan_speed[i];
+        tail_fan_speed[i] = (block_buffer[block_buffer_tail].fan_speed[i] * uint16_t(thermalManager.fan_speed_scaler[i])) >> 7;
     #endif
 
     block_t* block;
@@ -1203,7 +1202,8 @@ void Planner::check_axes_activity() {
   }
   else {
     #if FAN_COUNT > 0
-      FANS_LOOP(i) tail_fan_speed[i] = fan_speed[i];
+      FANS_LOOP(i)
+        tail_fan_speed[i] = (thermalManager.fan_speed[i] * uint16_t(thermalManager.fan_speed_scaler[i])) >> 7;
     #endif
 
     #if ENABLED(BARICUDA)
@@ -1903,7 +1903,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
   #endif
 
   #if FAN_COUNT > 0
-    FANS_LOOP(i) block->fan_speed[i] = fan_speed[i];
+    FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
   #endif
 
   #if ENABLED(BARICUDA)
diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp
index 76be571444f..9247aedf43c 100644
--- a/Marlin/src/module/probe.cpp
+++ b/Marlin/src/module/probe.cpp
@@ -268,31 +268,13 @@ float zprobe_zoffset; // Initialized by settings.load()
 
 #endif // Z_PROBE_ALLEN_KEY
 
-#if ENABLED(PROBING_FANS_OFF)
-
-  void fans_pause(const bool p) {
-    if (p != fans_paused) {
-      fans_paused = p;
-      if (p)
-        for (uint8_t x = 0; x < FAN_COUNT; x++) {
-          paused_fan_speed[x] = fan_speed[x];
-          fan_speed[x] = 0;
-        }
-      else
-        for (uint8_t x = 0; x < FAN_COUNT; x++)
-          fan_speed[x] = paused_fan_speed[x];
-    }
-  }
-
-#endif // PROBING_FANS_OFF
-
 #if QUIET_PROBING
   void probing_pause(const bool p) {
     #if ENABLED(PROBING_HEATERS_OFF)
       thermalManager.pause(p);
     #endif
     #if ENABLED(PROBING_FANS_OFF)
-      fans_pause(p);
+      thermalManager.set_fans_paused(p);
     #endif
     #if ENABLED(PROBING_STEPPERS_OFF)
       disable_e_steppers();
diff --git a/Marlin/src/module/probe.h b/Marlin/src/module/probe.h
index 830911a6ba2..138974bda6e 100644
--- a/Marlin/src/module/probe.h
+++ b/Marlin/src/module/probe.h
@@ -58,10 +58,6 @@
   void probing_pause(const bool p);
 #endif
 
-#if ENABLED(PROBING_FANS_OFF)
-  void fans_pause(const bool p);
-#endif
-
 #if ENABLED(BLTOUCH)
   void bltouch_command(int angle);
   bool set_bltouch_deployed(const bool deploy);
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index 915bb5a859e..e08b2332b4b 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -55,6 +55,10 @@
   #include "../feature/leds/printer_event_leds.h"
 #endif
 
+#if ENABLED(SINGLENOZZLE)
+  #include "tool_change.h"
+#endif
+
 #if HOTEND_USES_THERMISTOR
   #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
     static void* heater_ttbl_map[2] = { (void*)HEATER_0_TEMPTABLE, (void*)HEATER_1_TEMPTABLE };
@@ -92,14 +96,99 @@ Temperature thermalManager;
 
 // public:
 
-float Temperature::current_temperature[HOTENDS] = { 0.0 };
-int16_t Temperature::current_temperature_raw[HOTENDS] = { 0 },
-        Temperature::target_temperature[HOTENDS] = { 0 };
+float Temperature::current_temperature[HOTENDS]; // = { 0.0 };
+int16_t Temperature::current_temperature_raw[HOTENDS], // = { 0 }
+        Temperature::target_temperature[HOTENDS]; // = { 0 }
 
 #if ENABLED(AUTO_POWER_E_FANS)
-  uint8_t Temperature::autofan_speed[HOTENDS] = { 0 };
+  uint8_t Temperature::autofan_speed[HOTENDS]; // = { 0 }
 #endif
 
+#if FAN_COUNT > 0
+
+  uint8_t Temperature::fan_speed[FAN_COUNT]; // = { 0 }
+
+  #if ENABLED(EXTRA_FAN_SPEED)
+    uint8_t Temperature::old_fan_speed[FAN_COUNT], Temperature::new_fan_speed[FAN_COUNT];
+
+    void Temperature::set_temp_fan_speed(const uint8_t fan, const int16_t tmp_temp) {
+      switch (tmp_temp) {
+        case 1:
+          set_fan_speed(fan, old_fan_speed[fan]);
+          break;
+        case 2:
+          old_fan_speed[fan] = fan_speed[fan];
+          set_fan_speed(fan, new_fan_speed[fan]);
+          break;
+        default:
+          new_fan_speed[fan] = MIN(tmp_temp, 255U);
+          break;
+      }
+    }
+
+  #endif
+
+  #if ENABLED(PROBING_FANS_OFF)
+    bool Temperature::fans_paused; // = false;
+    uint8_t Temperature::paused_fan_speed[FAN_COUNT]; // = { 0 }
+  #endif
+
+  #if ENABLED(ADAPTIVE_FAN_SLOWING)
+    uint8_t Temperature::fan_speed_scaler[FAN_COUNT] = ARRAY_N(FAN_COUNT, 128, 128, 128, 128, 128, 128);
+  #endif
+
+  #if HAS_LCD_MENU
+
+    uint8_t Temperature::lcd_tmpfan_speed[
+      #if ENABLED(SINGLENOZZLE)
+        MAX(EXTRUDERS, FAN_COUNT)
+      #else
+        FAN_COUNT
+      #endif
+    ]; // = { 0 }
+
+  #endif
+
+  void Temperature::set_fan_speed(uint8_t target, uint16_t speed) {
+
+    NOMORE(speed, 255U);
+
+    #if ENABLED(SINGLENOZZLE)
+      if (target != active_extruder) {
+        if (target < EXTRUDERS) singlenozzle_fan_speed[target] = speed;
+        return;
+      }
+      target = 0; // Always use fan index 0 with SINGLENOZZLE
+    #endif
+
+    if (target >= FAN_COUNT) return;
+    
+    fan_speed[target] = speed;
+    #if ENABLED(ULTRA_LCD)
+      lcd_tmpfan_speed[target] = speed;
+    #endif
+  }
+
+  #if ENABLED(PROBING_FANS_OFF)
+
+    void Temperature::set_fans_paused(const bool p) {
+      if (p != fans_paused) {
+        fans_paused = p;
+        if (p)
+          for (uint8_t x = 0; x < FAN_COUNT; x++) {
+            paused_fan_speed[x] = fan_speed[x];
+            fan_speed[x] = 0;
+          }
+        else
+          for (uint8_t x = 0; x < FAN_COUNT; x++)
+            fan_speed[x] = paused_fan_speed[x];
+      }
+    }
+
+  #endif // PROBING_FANS_OFF
+
+#endif // FAN_COUNT > 0
+
 #if HAS_HEATED_BED
   float Temperature::current_temperature_bed = 0.0;
   int16_t Temperature::current_temperature_bed_raw = 0,
@@ -1529,18 +1618,38 @@ void Temperature::init() {
     switch (*state) {
       // Inactive state waits for a target temperature to be set
       case TRInactive: break;
+
       // When first heating, wait for the temperature to be reached then go to Stable state
       case TRFirstHeating:
         if (current < tr_target_temperature[heater_index]) break;
         *state = TRStable;
+
       // While the temperature is stable watch for a bad temperature
       case TRStable:
+
+        #if ENABLED(ADAPTIVE_FAN_SLOWING) && FAN_COUNT > 0
+          if (heater_id >= 0) {
+            const int fan_index = MIN(heater_id, FAN_COUNT - 1);
+            if (fan_speed[fan_index] == 0 || current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.25f))
+              fan_speed_scaler[fan_index] = 128;
+            else if (current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.3335f))
+              fan_speed_scaler[fan_index] = 96;
+            else if (current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.5f))
+              fan_speed_scaler[fan_index] = 64;
+            else if (current >= tr_target_temperature[heater_id] - (hysteresis_degc * 0.8f))
+              fan_speed_scaler[fan_index] = 32;
+            else
+              fan_speed_scaler[fan_index] = 0;
+          }
+        #endif
+
         if (current >= tr_target_temperature[heater_index] - hysteresis_degc) {
           *timer = millis() + period_seconds * 1000UL;
           break;
         }
         else if (PENDING(millis(), *timer)) break;
         *state = TRRunaway;
+
       case TRRunaway:
         _temp_error(heater_id, PSTR(MSG_T_THERMAL_RUNAWAY), TEMP_ERR_PSTR(MSG_THERMAL_RUNAWAY, heater_id));
     }
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index 31f8f2eb3e5..8468f059b2b 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -320,6 +320,71 @@ class Temperature {
       static float analog_to_celsiusChamber(const int raw);
     #endif
 
+    #if FAN_COUNT > 0
+
+      static uint8_t fan_speed[FAN_COUNT];
+      #define FANS_LOOP(I) LOOP_L_N(I, FAN_COUNT)
+
+      static void set_fan_speed(const uint8_t target, const uint16_t speed);
+
+      #if ENABLED(PROBING_FANS_OFF)
+        static bool fans_paused;
+        static uint8_t paused_fan_speed[FAN_COUNT];
+      #endif
+
+      static constexpr inline uint8_t fanPercent(const uint8_t speed) { return (int(speed) * 100 + 127) / 255; }
+
+      #if ENABLED(ADAPTIVE_FAN_SLOWING)
+        static uint8_t fan_speed_scaler[FAN_COUNT];
+      #else
+        static constexpr uint8_t fan_speed_scaler[FAN_COUNT] = ARRAY_N(FAN_COUNT, 128, 128, 128, 128, 128, 128);
+      #endif
+
+      static inline uint8_t lcd_fanSpeedActual(const uint8_t target) {
+        return (fan_speed[target] * uint16_t(fan_speed_scaler[target])) >> 7;
+      }
+
+      #if ENABLED(EXTRA_FAN_SPEED)
+        static uint8_t old_fan_speed[FAN_COUNT], new_fan_speed[FAN_COUNT];
+        static void set_temp_fan_speed(const uint8_t fan, const int16_t tmp_temp);
+      #endif
+
+      #if HAS_LCD_MENU
+
+        static uint8_t lcd_tmpfan_speed[
+          #if ENABLED(SINGLENOZZLE)
+            MAX(EXTRUDERS, FAN_COUNT)
+          #else
+            FAN_COUNT
+          #endif
+        ];
+
+        static inline void lcd_setFanSpeed(const uint8_t target) { set_fan_speed(target, lcd_tmpfan_speed[target]); }
+
+        #if HAS_FAN0
+          FORCE_INLINE static void lcd_setFanSpeed0() { lcd_setFanSpeed(0); }
+        #endif
+        #if HAS_FAN1 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 1)
+          FORCE_INLINE static void lcd_setFanSpeed1() { lcd_setFanSpeed(1); }
+        #endif
+        #if HAS_FAN2 || (ENABLED(SINGLENOZZLE) && EXTRUDERS > 2)
+          FORCE_INLINE static void lcd_setFanSpeed2() { lcd_setFanSpeed(2); }
+        #endif
+
+      #endif // HAS_LCD_MENU
+
+      #if ENABLED(PROBING_FANS_OFF)
+        void set_fans_paused(const bool p);
+      #endif
+
+    #endif // FAN_COUNT > 0
+
+    static inline void zero_fan_speeds() {
+      #if FAN_COUNT > 0
+        FANS_LOOP(i) fan_speed[i] = 0;
+      #endif
+    }
+
     /**
      * Called from the Temperature ISR
      */
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 2125736cf5f..65fcabd5a77 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -674,8 +674,8 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
 
         #if ENABLED(SINGLENOZZLE)
           #if FAN_COUNT > 0
-            singlenozzle_fan_speed[active_extruder] = fan_speed[0];
-            fan_speed[0] = singlenozzle_fan_speed[tmp_extruder];
+            singlenozzle_fan_speed[active_extruder] = thermalManager.fan_speed[0];
+            thermalManager.fan_speed[0] = singlenozzle_fan_speed[tmp_extruder];
           #endif
 
           singlenozzle_temp[active_extruder] = thermalManager.target_temperature[0];
diff --git a/buildroot/share/tests/LPC1768_tests b/buildroot/share/tests/LPC1768_tests
index 371619b04d9..f79cefa00c1 100755
--- a/buildroot/share/tests/LPC1768_tests
+++ b/buildroot/share/tests/LPC1768_tests
@@ -36,7 +36,7 @@ opt_set EXTRUDERS 2
 opt_set TEMP_SENSOR_0 1
 opt_set TEMP_SENSOR_1 5
 opt_set TEMP_SENSOR_BED 1
-opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT \
+opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT ADAPTIVE_FAN_SLOWING \
            FILAMENT_WIDTH_SENSOR FILAMENT_LCD_DISPLAY \
            FIX_MOUNTED_PROBE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \
            BABYSTEPPING BABYSTEP_XY BABYSTEP_ZPROBE_OFFSET BABYSTEP_ZPROBE_GFX_OVERLAY \