From 6fe387b6f0722033e6cca96fd5e8215ea7b162eb Mon Sep 17 00:00:00 2001
From: Scott Lahteine <thinkyhead@users.noreply.github.com>
Date: Sun, 15 Jan 2023 06:48:17 -0600
Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Adjust=20PI?=
 =?UTF-8?q?D=20/=20MPC=20/=20ProUI?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Changes to simplify #25232 WIP
---
 Marlin/Configuration_adv.h                    |  6 +-
 Marlin/src/gcode/geometry/M206_M428.cpp       |  2 +-
 Marlin/src/gcode/temp/M303.cpp                | 19 +----
 Marlin/src/gcode/temp/M306.cpp                | 28 +++----
 Marlin/src/inc/Conditionals_post.h            |  3 +
 Marlin/src/lcd/e3v2/proui/dwin.cpp            | 37 ++++++---
 Marlin/src/lcd/e3v2/proui/dwin.h              | 27 +++----
 Marlin/src/lcd/e3v2/proui/plot.cpp            |  2 +-
 Marlin/src/lcd/e3v2/proui/plot.h              |  2 +-
 .../src/lcd/extui/dgus/DGUSScreenHandler.cpp  |  4 +-
 .../lcd/extui/dgus/DGUSScreenHandlerBase.h    |  1 +
 Marlin/src/lcd/extui/dgus/dgus_extui.cpp      | 12 +--
 .../extui/dgus_reloaded/DGUSScreenHandler.cpp |  4 +-
 .../extui/dgus_reloaded/DGUSScreenHandler.h   |  8 +-
 Marlin/src/lcd/extui/example/example.cpp      | 10 +--
 .../ftdi_eve_touch_ui/ftdi_eve_extui.cpp      |  4 +-
 Marlin/src/lcd/extui/malyan/malyan_extui.cpp  |  4 +-
 Marlin/src/lcd/extui/ui_api.h                 |  2 +-
 Marlin/src/lcd/language/language_de.h         |  4 +-
 Marlin/src/lcd/language/language_en.h         | 15 ++--
 Marlin/src/lcd/language/language_fr.h         |  2 +-
 Marlin/src/lcd/language/language_gl.h         |  2 +-
 Marlin/src/lcd/language/language_hu.h         |  2 +-
 Marlin/src/lcd/language/language_it.h         |  4 +-
 Marlin/src/lcd/language/language_ro.h         |  2 +-
 Marlin/src/lcd/language/language_ru.h         |  2 +-
 Marlin/src/lcd/language/language_sk.h         |  4 +-
 Marlin/src/lcd/language/language_sv.h         |  2 +-
 Marlin/src/lcd/language/language_uk.h         |  2 +-
 Marlin/src/lcd/language/language_zh_CN.h      |  2 +-
 Marlin/src/lcd/menu/menu_advanced.cpp         | 22 +++---
 Marlin/src/module/settings.cpp                | 20 +++--
 Marlin/src/module/temperature.cpp             | 76 ++++++++++---------
 Marlin/src/module/temperature.h               | 10 ++-
 34 files changed, 181 insertions(+), 165 deletions(-)

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index ee531091428..71f46bfe8a7 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -1429,12 +1429,10 @@
 
 #endif // HAS_MARLINUI_MENU
 
-#if ANY(HAS_DISPLAY, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI)
+#if HAS_DISPLAY
   //#define SOUND_MENU_ITEM   // Add a mute option to the LCD menu
   #define SOUND_ON_DEFAULT    // Buzzer/speaker default enabled state
-#endif
 
-#if EITHER(HAS_DISPLAY, DWIN_LCD_PROUI)
   // The timeout to return to the status screen from sub-menus
   //#define LCD_TIMEOUT_TO_STATUS 15000   // (ms)
 
@@ -1483,7 +1481,7 @@
     #endif
   #endif
 
-#endif // HAS_DISPLAY || DWIN_LCD_PROUI
+#endif // HAS_DISPLAY
 
 // Add 'M73' to set print job progress, overrides Marlin's built-in estimate
 //#define SET_PROGRESS_MANUALLY
diff --git a/Marlin/src/gcode/geometry/M206_M428.cpp b/Marlin/src/gcode/geometry/M206_M428.cpp
index 494b2115b82..b12e6806053 100644
--- a/Marlin/src/gcode/geometry/M206_M428.cpp
+++ b/Marlin/src/gcode/geometry/M206_M428.cpp
@@ -91,7 +91,7 @@ void GcodeSuite::M428() {
       diff[i] = -current_position[i];
     if (!WITHIN(diff[i], -20, 20)) {
       SERIAL_ERROR_MSG(STR_ERR_M428_TOO_FAR);
-      LCD_ALERTMESSAGE_F("Err: Too far!");
+      LCD_ALERTMESSAGE(MSG_ERR_M428_TOO_FAR);
       ERR_BUZZ();
       return;
     }
diff --git a/Marlin/src/gcode/temp/M303.cpp b/Marlin/src/gcode/temp/M303.cpp
index 820b1556d61..e0ad26027e6 100644
--- a/Marlin/src/gcode/temp/M303.cpp
+++ b/Marlin/src/gcode/temp/M303.cpp
@@ -67,8 +67,8 @@ void GcodeSuite::M303() {
     default:
       SERIAL_ECHOPGM(STR_PID_AUTOTUNE);
       SERIAL_ECHOLNPGM(STR_PID_BAD_HEATER_ID);
-      TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_BAD_EXTRUDER_NUM));
-      TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_BAD_EXTRUDER_NUM));
+      TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_BAD_HEATER_ID));
+      TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_BAD_HEATER_ID));
       return;
   }
 
@@ -78,20 +78,9 @@ void GcodeSuite::M303() {
   const celsius_t temp = seenS ? parser.value_celsius() : default_temp;
   const bool u = parser.boolval('U');
 
-  #if ENABLED(DWIN_LCD_PROUI) && EITHER(PIDTEMP, PIDTEMPBED)
-    if (seenC) HMI_data.PidCycles = c;
-    if (seenS) {
-      switch (hid) {
-        OPTCODE(PIDTEMP,    case 0 ... HOTENDS - 1: HMI_data.HotendPidT = temp; break)
-        OPTCODE(PIDTEMPBED, case H_BED:             HMI_data.BedPidT = temp;    break)
-        default: break;
-      }
-    }
-  #endif
+  TERN_(DWIN_PID_TUNE, DWIN_StartM303(seenC, c, seenS, hid, temp));
 
-  #if DISABLED(BUSY_WHILE_HEATING)
-    KEEPALIVE_STATE(NOT_BUSY);
-  #endif
+  IF_DISABLED(BUSY_WHILE_HEATING, KEEPALIVE_STATE(NOT_BUSY));
 
   LCD_MESSAGE(MSG_PID_AUTOTUNE);
   thermalManager.PID_autotune(temp, hid, c, u);
diff --git a/Marlin/src/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp
index c6b700eac3b..582eb13f81f 100644
--- a/Marlin/src/gcode/temp/M306.cpp
+++ b/Marlin/src/gcode/temp/M306.cpp
@@ -52,15 +52,15 @@ void GcodeSuite::M306() {
 
   if (parser.seen("ACFPRH")) {
     const heater_id_t hid = (heater_id_t)parser.intval('E', 0);
-    MPC_t &constants = thermalManager.temp_hotend[hid].constants;
-    if (parser.seenval('P')) constants.heater_power = parser.value_float();
-    if (parser.seenval('C')) constants.block_heat_capacity = parser.value_float();
-    if (parser.seenval('R')) constants.sensor_responsiveness = parser.value_float();
-    if (parser.seenval('A')) constants.ambient_xfer_coeff_fan0 = parser.value_float();
+    MPC_t &mpc = thermalManager.temp_hotend[hid].mpc;
+    if (parser.seenval('P')) mpc.heater_power = parser.value_float();
+    if (parser.seenval('C')) mpc.block_heat_capacity = parser.value_float();
+    if (parser.seenval('R')) mpc.sensor_responsiveness = parser.value_float();
+    if (parser.seenval('A')) mpc.ambient_xfer_coeff_fan0 = parser.value_float();
     #if ENABLED(MPC_INCLUDE_FAN)
-      if (parser.seenval('F')) constants.fan255_adjustment = parser.value_float() - constants.ambient_xfer_coeff_fan0;
+      if (parser.seenval('F')) mpc.applyFanAdjustment(parser.value_float());
     #endif
-    if (parser.seenval('H')) constants.filament_heat_capacity_permm = parser.value_float();
+    if (parser.seenval('H')) mpc.filament_heat_capacity_permm = parser.value_float();
     return;
   }
 
@@ -71,16 +71,16 @@ void GcodeSuite::M306_report(const bool forReplay/*=true*/) {
   report_heading(forReplay, F("Model predictive control"));
   HOTEND_LOOP() {
     report_echo_start(forReplay);
-    MPC_t& constants = thermalManager.temp_hotend[e].constants;
+    MPC_t &mpc = thermalManager.temp_hotend[e].mpc;
     SERIAL_ECHOPGM("  M306 E", e);
-    SERIAL_ECHOPAIR_F(" P", constants.heater_power, 2);
-    SERIAL_ECHOPAIR_F(" C", constants.block_heat_capacity, 2);
-    SERIAL_ECHOPAIR_F(" R", constants.sensor_responsiveness, 4);
-    SERIAL_ECHOPAIR_F(" A", constants.ambient_xfer_coeff_fan0, 4);
+    SERIAL_ECHOPAIR_F(" P", mpc.heater_power, 2);
+    SERIAL_ECHOPAIR_F(" C", mpc.block_heat_capacity, 2);
+    SERIAL_ECHOPAIR_F(" R", mpc.sensor_responsiveness, 4);
+    SERIAL_ECHOPAIR_F(" A", mpc.ambient_xfer_coeff_fan0, 4);
     #if ENABLED(MPC_INCLUDE_FAN)
-      SERIAL_ECHOPAIR_F(" F", constants.ambient_xfer_coeff_fan0 + constants.fan255_adjustment, 4);
+      SERIAL_ECHOPAIR_F(" F", mpc.fanCoefficient(), 4);
     #endif
-    SERIAL_ECHOPAIR_F(" H", constants.filament_heat_capacity_permm, 4);
+    SERIAL_ECHOPAIR_F(" H", mpc.filament_heat_capacity_permm, 4);
     SERIAL_EOL();
   }
 }
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index 8fe9a408f22..515d5f7984a 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -2504,6 +2504,9 @@
 // PID heating
 #if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER)
   #define HAS_PID_HEATING 1
+  #if ENABLED(DWIN_LCD_PROUI) && EITHER(PIDTEMP, PIDTEMPBED)
+    #define DWIN_PID_TUNE 1
+  #endif
 #endif
 
 // Thermal protection
diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp
index 621b3d0dd39..4be08194413 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin.cpp
+++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp
@@ -1500,9 +1500,10 @@ void DWIN_LevelingDone() {
 
 // PID process
 
-#if HAS_PIDPLOT
+#if BOTH(HAS_PIDPLOT, DWIN_PID_TUNE)
+
   void DWIN_Draw_PIDPopup() {
-    frame_rect_t gfrm = {40, 180, DWIN_WIDTH - 80, 120};
+    frame_rect_t gfrm = { 40, 180, DWIN_WIDTH - 80, 120 };
     DWINUI::ClearMainArea();
     Draw_Popup_Bkgd();
     DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 100, GET_TEXT_F(MSG_PID_AUTOTUNE));
@@ -1525,9 +1526,21 @@ void DWIN_LevelingDone() {
       default: break;
     }
   }
+
 #endif
 
-#if EITHER(PIDTEMP, PIDTEMPBED)
+#if DWIN_PID_TUNE
+
+  void DWIN_StartM303(const bool seenC, const int c, const bool seenS, const heater_id_t hid, const celsius_t temp) {
+    if (seenC) HMI_data.PidCycles = c;
+    if (seenS) {
+      switch (hid) {
+        OPTCODE(PIDTEMP,    case 0 ... HOTENDS - 1: HMI_data.HotendPidT = temp; break)
+        OPTCODE(PIDTEMPBED, case H_BED:             HMI_data.BedPidT = temp;    break)
+        default: break;
+      }
+    }
+  }
 
   void DWIN_PidTuning(pidresult_t result) {
     HMI_value.pidresult = result;
@@ -1541,9 +1554,9 @@ void DWIN_LevelingDone() {
             DWIN_Draw_Popup(ICON_TempTooHigh, GET_TEXT_F(MSG_PID_AUTOTUNE), F("for Nozzle is running."));
           #endif
           break;
-        case PID_BAD_EXTRUDER_NUM:
+        case PID_BAD_HEATER_ID:
           checkkey = last_checkkey;
-          DWIN_Popup_Confirm(ICON_TempTooLow, GET_TEXT_F(MSG_PID_AUTOTUNE_FAILED), GET_TEXT_F(MSG_BAD_EXTRUDER_NUM));
+          DWIN_Popup_Confirm(ICON_TempTooLow, GET_TEXT_F(MSG_PID_AUTOTUNE_FAILED), GET_TEXT_F(MSG_BAD_HEATER_ID));
           break;
       #endif
       #if ENABLED(PIDTEMPBED)
@@ -1568,11 +1581,13 @@ void DWIN_LevelingDone() {
         checkkey = last_checkkey;
         DWIN_Popup_Confirm(ICON_TempTooLow, GET_TEXT_F(MSG_PID_AUTOTUNE), GET_TEXT_F(MSG_BUTTON_DONE));
         break;
-      default: checkkey = last_checkkey; break;
+      default:
+        checkkey = last_checkkey;
+        break;
     }
   }
 
-#endif // PIDTEMP || PIDTEMPBED
+#endif // DWIN_PID_TUNE
 
 // Started a Print Job
 void DWIN_Print_Started() {
@@ -1667,7 +1682,7 @@ void DWIN_SetDataDefaults() {
   DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color);
   TERN_(PIDTEMP, HMI_data.HotendPidT = DEF_HOTENDPIDT);
   TERN_(PIDTEMPBED, HMI_data.BedPidT = DEF_BEDPIDT);
-  TERN_(HAS_PID_HEATING, HMI_data.PidCycles = DEF_PIDCYCLES);
+  TERN_(DWIN_PID_TUNE, HMI_data.PidCycles = DEF_PIDCYCLES);
   #if ENABLED(PREVENT_COLD_EXTRUSION)
     HMI_data.ExtMinT = EXTRUDE_MINTEMP;
     ApplyExtMinT();
@@ -2057,7 +2072,7 @@ void SetMoveZ() { HMI_value.axis = Z_AXIS; SetPFloatOnClick(Z_MIN_POS, Z_MAX_POS
   }
 #endif
 
-#if EITHER(PIDTEMP, PIDTEMPBED)
+#if DWIN_PID_TUNE
   void SetPID(celsius_t t, heater_id_t h) {
     char cmd[53] = "";
     char str_1[5] = "", str_2[5] = "";
@@ -2523,7 +2538,7 @@ void SetStepsZ() { HMI_value.axis = Z_AXIS, SetPFloatOnClick( MIN_STEP, MAX_STEP
   void SetBedPidT() { SetPIntOnClick(MIN_BEDTEMP, MAX_BEDTEMP); }
 #endif
 
-#if EITHER(PIDTEMP, PIDTEMPBED)
+#if DWIN_PID_TUNE
   void SetPidCycles() { SetPIntOnClick(3, 50); }
   void SetKp() { SetPFloatOnClick(0, 1000, 2); }
   void ApplyPIDi() {
@@ -2694,7 +2709,7 @@ void onDrawGetColorItem(MenuItemClass* menuitem, int8_t line) {
   DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MYPOS(line + 1), 240);
 }
 
-#if EITHER(PIDTEMP, PIDTEMPBED)
+#if DWIN_PID_TUNE
   void onDrawPIDi(MenuItemClass* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, unscalePID_i(*(float*)static_cast<MenuItemPtrClass*>(menuitem)->value)); }
   void onDrawPIDd(MenuItemClass* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, unscalePID_d(*(float*)static_cast<MenuItemPtrClass*>(menuitem)->value)); }
 #endif
diff --git a/Marlin/src/lcd/e3v2/proui/dwin.h b/Marlin/src/lcd/e3v2/proui/dwin.h
index cac64b8ce57..bc050abd2e1 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin.h
+++ b/Marlin/src/lcd/e3v2/proui/dwin.h
@@ -76,7 +76,7 @@ enum processID : uint8_t {
 enum pidresult_t : uint8_t {
   PIDTEMP_START = 0,
   PIDTEMPBED_START,
-  PID_BAD_EXTRUDER_NUM,
+  PID_BAD_HEATER_ID,
   PID_TEMP_TOO_HIGH,
   PID_TUNING_TIMEOUT,
   PID_DONE,
@@ -107,14 +107,14 @@ typedef struct {
   uint16_t Coordinate_Color;
 
   // Temperatures
-  #if ENABLED(PIDTEMP)
-    int16_t HotendPidT = DEF_HOTENDPIDT;
-  #endif
-  #if ENABLED(PIDTEMPBED)
-    int16_t BedPidT = DEF_BEDPIDT;
-  #endif
-  #if (HAS_HOTEND || HAS_HEATED_BED) && HAS_PID_HEATING
+  #if DWIN_PID_TUNE
     int16_t PidCycles = DEF_PIDCYCLES;
+    #if ENABLED(PIDTEMP)
+      int16_t HotendPidT = DEF_HOTENDPIDT;
+    #endif
+    #if ENABLED(PIDTEMPBED)
+      int16_t BedPidT = DEF_BEDPIDT;
+    #endif
   #endif
   #if ENABLED(PREVENT_COLD_EXTRUSION)
     int16_t ExtMinT = EXTRUDE_MINTEMP;
@@ -141,8 +141,8 @@ static constexpr size_t eeprom_data_size = sizeof(HMI_data_t);
 
 typedef struct {
   int8_t Color[3];                    // Color components
-  #if HAS_PID_HEATING
-    tempcontrol_t pidresult = PID_DONE;
+  #if DWIN_PID_TUNE
+    pidresult_t pidresult = PID_DONE;
   #endif
   uint8_t Select          = 0;        // Auxiliary selector variable
   AxisEnum axis           = X_AXIS;   // Axis Select
@@ -358,8 +358,10 @@ void Draw_Steps_Menu();
 #endif
 
 // PID
-#if HAS_PID_HEATING
-  void DWIN_PidTuning(tempcontrol_t result);
+#if DWIN_PID_TUNE
+  #include "../../../module/temperature.h"
+  void DWIN_StartM303(const bool seenC, const int c, const bool seenS, const heater_id_t hid, const celsius_t temp);
+  void DWIN_PidTuning(pidresult_t result);
   #if ENABLED(PIDTEMP)
     void Draw_HotendPID_Menu();
   #endif
@@ -367,4 +369,3 @@ void Draw_Steps_Menu();
     void Draw_BedPID_Menu();
   #endif
 #endif
-#endif
diff --git a/Marlin/src/lcd/e3v2/proui/plot.cpp b/Marlin/src/lcd/e3v2/proui/plot.cpp
index 75917320a45..53178e3ea70 100644
--- a/Marlin/src/lcd/e3v2/proui/plot.cpp
+++ b/Marlin/src/lcd/e3v2/proui/plot.cpp
@@ -74,7 +74,7 @@ void PlotClass::Draw(const frame_rect_t frame, const float max, const float ref)
   DWIN_Draw_HLine(Color_Red, frame.x, r, frame.w);
 }
 
-void PlotClass::Update(const float value) {
+void PlotClass::Update(const_float_t value) {
   if (!scale) return;
   uint16_t y = round((y2) - value * scale);
   if (grphpoints < grphframe.w) {
diff --git a/Marlin/src/lcd/e3v2/proui/plot.h b/Marlin/src/lcd/e3v2/proui/plot.h
index ea15255fe53..2663776dc4f 100644
--- a/Marlin/src/lcd/e3v2/proui/plot.h
+++ b/Marlin/src/lcd/e3v2/proui/plot.h
@@ -48,7 +48,7 @@
 class PlotClass {
 public:
   void Draw(frame_rect_t frame, float max, float ref = 0);
-  void Update(float value);
+  void Update(const_float_t value);
 };
 
 extern PlotClass Plot;
diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp
index 37543a237c0..82dbeee4112 100644
--- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp
+++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp
@@ -295,11 +295,11 @@ void DGUSScreenHandler::DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var)
 
     // Don't let the user in the dark why there is no reaction.
     if (!ExtUI::isMediaInserted()) {
-      setstatusmessagePGM(GET_TEXT(MSG_NO_MEDIA));
+      setstatusmessage(GET_TEXT_F(MSG_NO_MEDIA));
       return;
     }
     if (card.flag.abort_sd_printing) {
-      setstatusmessagePGM(GET_TEXT(MSG_MEDIA_ABORTING));
+      setstatusmessage(GET_TEXT_F(MSG_MEDIA_ABORTING));
       return;
     }
   }
diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h b/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h
index 07a108e8466..340938c9790 100644
--- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h
+++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h
@@ -51,6 +51,7 @@ public:
   static void setstatusmessage(const char *msg);
   // The same for messages from Flash
   static void setstatusmessagePGM(PGM_P const msg);
+  static void setstatusmessage(FSTR_P const fmsg) { setstatusmessagePGM(FTOP(fmsg)); }
   // Callback for VP "Display wants to change screen on idle printer"
   static void ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr);
   // Callback for VP "Screen has been changed"
diff --git a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp
index b041687a14f..382c5eb1bef 100644
--- a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp
+++ b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp
@@ -137,19 +137,19 @@ namespace ExtUI {
       // Called for temperature PID tuning result
       switch (rst) {
         case PID_STARTED:
-          ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_AUTOTUNE));
+          ScreenHandler.setstatusmessage(GET_TEXT_F(MSG_PID_AUTOTUNE));
           break;
-        case PID_BAD_EXTRUDER_NUM:
-          ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_BAD_EXTRUDER_NUM));
+        case PID_BAD_HEATER_ID:
+          ScreenHandler.setstatusmessage(GET_TEXT_F(MSG_PID_BAD_HEATER_ID));
           break;
         case PID_TEMP_TOO_HIGH:
-          ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_TEMP_TOO_HIGH));
+          ScreenHandler.setstatusmessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
           break;
         case PID_TUNING_TIMEOUT:
-          ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_TIMEOUT));
+          ScreenHandler.setstatusmessage(GET_TEXT_F(MSG_PID_TIMEOUT));
           break;
         case PID_DONE:
-          ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_AUTOTUNE_DONE));
+          ScreenHandler.setstatusmessage(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE));
           break;
       }
       ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
diff --git a/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp
index 4d758ae5ef7..3d0896a67cf 100644
--- a/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp
+++ b/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp
@@ -325,8 +325,8 @@ void DGUSScreenHandler::FilamentRunout(const ExtUI::extruder_t extruder) {
       case ExtUI::PID_STARTED:
         SetStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE));
         break;
-      case ExtUI::PID_BAD_EXTRUDER_NUM:
-        SetStatusMessage(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
+      case ExtUI::PID_BAD_HEATER_ID:
+        SetStatusMessage(GET_TEXT_F(MSG_PID_BAD_HEATER_ID));
         break;
       case ExtUI::PID_TEMP_TOO_HIGH:
         SetStatusMessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
diff --git a/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h b/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h
index cc59bda6d7f..6a00a4f72af 100644
--- a/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h
+++ b/Marlin/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h
@@ -72,10 +72,10 @@ public:
   static void SetMessageLine(const char* msg, uint8_t line);
   static void SetMessageLinePGM(PGM_P msg, uint8_t line);
 
-  static void SetStatusMessage(const char* msg, const millis_t duration = DGUS_STATUS_EXPIRATION_MS);
-  static void SetStatusMessage(FSTR_P const msg, const millis_t duration = DGUS_STATUS_EXPIRATION_MS);
+  static void SetStatusMessage(const char* msg, const millis_t duration=DGUS_STATUS_EXPIRATION_MS);
+  static void SetStatusMessage(FSTR_P const msg, const millis_t duration=DGUS_STATUS_EXPIRATION_MS);
 
-  static void ShowWaitScreen(DGUS_Screen return_screen, bool has_continue = false);
+  static void ShowWaitScreen(DGUS_Screen return_screen, bool has_continue=false);
 
   static DGUS_Screen GetCurrentScreen();
   static void TriggerScreenChange(DGUS_Screen screen);
@@ -115,7 +115,7 @@ private:
   static const DGUS_Addr* FindScreenAddrList(DGUS_Screen screen);
   static bool CallScreenSetup(DGUS_Screen screen);
 
-  static void MoveToScreen(DGUS_Screen screen, bool abort_wait = false);
+  static void MoveToScreen(DGUS_Screen screen, bool abort_wait=false);
   static bool SendScreenVPData(DGUS_Screen screen, bool complete_update);
 
   static bool settings_ready;
diff --git a/Marlin/src/lcd/extui/example/example.cpp b/Marlin/src/lcd/extui/example/example.cpp
index 6ef20cf5f0f..27269a9bee7 100644
--- a/Marlin/src/lcd/extui/example/example.cpp
+++ b/Marlin/src/lcd/extui/example/example.cpp
@@ -121,11 +121,11 @@ namespace ExtUI {
     void onPidTuning(const result_t rst) {
       // Called for temperature PID tuning result
       switch (rst) {
-        case PID_STARTED:          break;
-        case PID_BAD_EXTRUDER_NUM: break;
-        case PID_TEMP_TOO_HIGH:    break;
-        case PID_TUNING_TIMEOUT:   break;
-        case PID_DONE:             break;
+        case PID_STARTED:        break;
+        case PID_BAD_HEATER_ID:  break;
+        case PID_TEMP_TOO_HIGH:  break;
+        case PID_TUNING_TIMEOUT: break;
+        case PID_DONE:           break;
       }
     }
   #endif
diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp
index 2ce9ed027e8..84de2c58712 100644
--- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp
+++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp
@@ -136,8 +136,8 @@ namespace ExtUI {
         case PID_STARTED:
           StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE));
           break;
-        case PID_BAD_EXTRUDER_NUM:
-          StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
+        case PID_BAD_HEATER_ID:
+          StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_BAD_HEATER_ID));
           break;
         case PID_TEMP_TOO_HIGH:
           StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
diff --git a/Marlin/src/lcd/extui/malyan/malyan_extui.cpp b/Marlin/src/lcd/extui/malyan/malyan_extui.cpp
index 945ff472e1a..8ed319e35c8 100644
--- a/Marlin/src/lcd/extui/malyan/malyan_extui.cpp
+++ b/Marlin/src/lcd/extui/malyan/malyan_extui.cpp
@@ -111,8 +111,8 @@ namespace ExtUI {
         case PID_STARTED:
           set_lcd_error(GET_TEXT_F(MSG_PID_AUTOTUNE));
           break;
-        case PID_BAD_EXTRUDER_NUM:
-          set_lcd_error(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
+        case PID_BAD_HEATER_ID:
+          set_lcd_error(GET_TEXT_F(MSG_PID_BAD_HEATER_ID));
           break;
         case PID_TEMP_TOO_HIGH:
           set_lcd_error(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h
index c2ce52ba4c1..b48dc94f8fe 100644
--- a/Marlin/src/lcd/extui/ui_api.h
+++ b/Marlin/src/lcd/extui/ui_api.h
@@ -61,7 +61,7 @@ namespace ExtUI {
   enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5, E6, E7 };
   enum heater_t   : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER, COOLER };
   enum fan_t      : uint8_t { FAN0, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7 };
-  enum result_t   : uint8_t { PID_STARTED, PID_BAD_EXTRUDER_NUM, PID_TEMP_TOO_HIGH, PID_TUNING_TIMEOUT, PID_DONE };
+  enum result_t   : uint8_t { PID_STARTED, PID_BAD_HEATER_ID, PID_TEMP_TOO_HIGH, PID_TUNING_TIMEOUT, PID_DONE };
 
   constexpr uint8_t extruderCount = EXTRUDERS;
   constexpr uint8_t hotendCount   = HOTENDS;
diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h
index a60da34d5f1..56f91e0ed23 100644
--- a/Marlin/src/lcd/language/language_de.h
+++ b/Marlin/src/lcd/language/language_de.h
@@ -343,10 +343,10 @@ namespace Language_de {
   LSTR MSG_PID_CYCLE                      = _UxGT("PID Zyklus");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("PID Tuning fertig");
   LSTR MSG_PID_AUTOTUNE_FAILED            = _UxGT("PID Autotune fehlge.!");
-  LSTR MSG_BAD_EXTRUDER_NUM               = _UxGT("ungültiger Extruder.");
+  LSTR MSG_BAD_HEATER_ID                  = _UxGT("ungültiger Extruder.");
   LSTR MSG_TEMP_TOO_HIGH                  = _UxGT("Temperatur zu hoch.");
   LSTR MSG_TIMEOUT                        = _UxGT("Timeout.");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Autotune fehlge.! Ungültiger Extruder");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Autotune fehlge.! Ungültiger Extruder");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Autotune fehlge.! Temperatur zu hoch.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Autotune fehlge.! Timeout.");
   LSTR MSG_MPC_MEASURING_AMBIENT          = _UxGT("teste Wärmeverlust");
diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h
index 9e67042d379..8352ef88862 100644
--- a/Marlin/src/lcd/language/language_en.h
+++ b/Marlin/src/lcd/language/language_en.h
@@ -107,6 +107,7 @@ namespace Language_en {
   LSTR MSG_HOME_OFFSET_Y                  = _UxGT("Home Offset Y");
   LSTR MSG_HOME_OFFSET_Z                  = _UxGT("Home Offset Z");
   LSTR MSG_HOME_OFFSETS_APPLIED           = _UxGT("Offsets Applied");
+  LSTR MSG_ERR_M428_TOO_FAR               = _UxGT("Err: Too far!");
   LSTR MSG_TRAMMING_WIZARD                = _UxGT("Tramming Wizard");
   LSTR MSG_SELECT_ORIGIN                  = _UxGT("Select Origin");
   LSTR MSG_LAST_VALUE_SP                  = _UxGT("Last value ");
@@ -364,20 +365,22 @@ namespace Language_en {
   LSTR MSG_PID_CYCLE                      = _UxGT("PID Cycles");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("PID tuning done");
   LSTR MSG_PID_AUTOTUNE_FAILED            = _UxGT("PID Autotune failed!");
-  LSTR MSG_BAD_EXTRUDER_NUM               = _UxGT("Bad extruder.");
+  LSTR MSG_BAD_HEATER_ID                  = _UxGT("Bad extruder.");
   LSTR MSG_TEMP_TOO_HIGH                  = _UxGT("Temperature too high.");
   LSTR MSG_TIMEOUT                        = _UxGT("Timeout.");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Autotune failed! Bad extruder.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Autotune failed! Bad extruder.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Autotune failed! Temperature too high.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Autotune failed! Timeout.");
   LSTR MSG_MPC_MEASURING_AMBIENT          = _UxGT("Testing heat loss");
+  LSTR MSG_MPC_HEATING_PAST_200           = _UxGT("Heating to >200C");
+  LSTR MSG_MPC_COOLING_TO_AMBIENT         = _UxGT("Cooling to ambient");
   LSTR MSG_MPC_AUTOTUNE                   = _UxGT("MPC Autotune");
   LSTR MSG_MPC_EDIT                       = _UxGT("Edit * MPC");
   LSTR MSG_MPC_POWER_E                    = _UxGT("Power *");
-  LSTR MSG_MPC_BLOCK_HEAT_CAPACITY_E      = _UxGT("Block C *");
-  LSTR MSG_SENSOR_RESPONSIVENESS_E        = _UxGT("Sensor res *");
-  LSTR MSG_MPC_AMBIENT_XFER_COEFF_E       = _UxGT("Ambient h *");
-  LSTR MSG_MPC_AMBIENT_XFER_COEFF_FAN_E   = _UxGT("Amb. h fan *");
+  LSTR MSG_MPC_BLOCK_HEAT_CAPACITY_E      = _UxGT("Heat Cap. *");
+  LSTR MSG_SENSOR_RESPONSIVENESS_E        = _UxGT("Sensor Resp. *");
+  LSTR MSG_MPC_AMBIENT_XFER_COEFF_E       = _UxGT("Ambient Co. *");
+  LSTR MSG_MPC_AMBIENT_XFER_COEFF_FAN_E   = _UxGT("Fan coeff. *");
   LSTR MSG_SELECT_E                       = _UxGT("Select *");
   LSTR MSG_ACC                            = _UxGT("Accel");
   LSTR MSG_JERK                           = _UxGT("Jerk");
diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h
index 02576f802c1..35e8502b940 100644
--- a/Marlin/src/lcd/language/language_fr.h
+++ b/Marlin/src/lcd/language/language_fr.h
@@ -269,7 +269,7 @@ namespace Language_fr {
   LSTR MSG_PID_AUTOTUNE                   = _UxGT("PID Autotune");
   LSTR MSG_PID_AUTOTUNE_E                 = _UxGT("PID Autotune *");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("Tuning PID terminé");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Echec Autotune! E incorrect");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Echec Autotune! E incorrect");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Echec Autotune! Temp. trop haute");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Echec Autotune! Opér. expirée");
   LSTR MSG_SELECT_E                       = _UxGT("Sélectionner *");
diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h
index 97b8b083178..abad80bbecb 100644
--- a/Marlin/src/lcd/language/language_gl.h
+++ b/Marlin/src/lcd/language/language_gl.h
@@ -263,7 +263,7 @@ namespace Language_gl {
   LSTR MSG_PID_AUTOTUNE                   = _UxGT("Auto-Sint. PID");
   LSTR MSG_PID_AUTOTUNE_E                 = _UxGT("Auto-Sint. PID *");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("Fin Auto-Sint PID");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Auto-Sint. fallida! Extrusor danado.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Auto-Sint. fallida! Extrusor danado.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Auto-Sint. fallida! Temperatura moi alta.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Auto-Sint. fallida! Tempo excedido.");
   LSTR MSG_SELECT_E                       = _UxGT("Escolla *");
diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h
index 0d70148c624..598da662cc7 100644
--- a/Marlin/src/lcd/language/language_hu.h
+++ b/Marlin/src/lcd/language/language_hu.h
@@ -306,7 +306,7 @@ namespace Language_hu {
   LSTR MSG_PID_AUTOTUNE_E                 = _UxGT("PID hangolás *");
   LSTR MSG_PID_CYCLE                      = _UxGT("PID ciklus");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("PID hangolás kész");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Hangolási hiba! Rossz adagoló.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Hangolási hiba! Rossz adagoló.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Hangolási hiba! Magas hömérséklet.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Hangolási hiba! Idötúllépés.");
   LSTR MSG_SELECT_E                       = _UxGT("Kiválaszt *");
diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h
index b0adb7791fe..12a9c572b5e 100644
--- a/Marlin/src/lcd/language/language_it.h
+++ b/Marlin/src/lcd/language/language_it.h
@@ -356,10 +356,10 @@ namespace Language_it {
   LSTR MSG_PID_CYCLE                      = _UxGT("Ciclo PID");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("Calibr.PID eseguita");
   LSTR MSG_PID_AUTOTUNE_FAILED            = _UxGT("Calibr.PID fallito!");
-  LSTR MSG_BAD_EXTRUDER_NUM               = _UxGT("Estrusore invalido.");
+  LSTR MSG_BAD_HEATER_ID                  = _UxGT("Estrusore invalido.");
   LSTR MSG_TEMP_TOO_HIGH                  = _UxGT("Temp.troppo alta.");
   LSTR MSG_TIMEOUT                        = _UxGT("Tempo scaduto.");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Calibrazione fallita! Estrusore errato.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Calibrazione fallita! Estrusore errato.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Calibrazione fallita! Temperatura troppo alta.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Calibrazione fallita! Tempo scaduto.");
   LSTR MSG_MPC_MEASURING_AMBIENT          = _UxGT("Testing heat loss");
diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h
index 57af0620235..48751f8cd2a 100644
--- a/Marlin/src/lcd/language/language_ro.h
+++ b/Marlin/src/lcd/language/language_ro.h
@@ -261,7 +261,7 @@ namespace Language_ro {
   LSTR MSG_PID_AUTOTUNE                   = _UxGT("PID Autotune");
   LSTR MSG_PID_AUTOTUNE_E                 = _UxGT("PID Autotune *");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("PID tuning done");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Autotune failed! Bad extruder.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Autotune failed! Bad extruder.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Autotune failed! Temperature too high.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Autotune failed! Timeout.");
   LSTR MSG_SELECT_E                       = _UxGT("Select *");
diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h
index 0af84d120a6..1f3c77752e7 100644
--- a/Marlin/src/lcd/language/language_ru.h
+++ b/Marlin/src/lcd/language/language_ru.h
@@ -382,7 +382,7 @@ namespace Language_ru {
   LSTR MSG_PID_AUTOTUNE                     = _UxGT("Автоподбор PID");
   LSTR MSG_PID_AUTOTUNE_E                   = _UxGT("Автоподбор PID *");
   LSTR MSG_PID_AUTOTUNE_DONE                = _UxGT("Подбор PID выполнен");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM             = _UxGT("Сбой автоподбора! Плохой экструдер.");
+  LSTR MSG_PID_BAD_HEATER_ID                = _UxGT("Сбой автоподбора! Плохой экструдер.");
   LSTR MSG_PID_TEMP_TOO_HIGH                = _UxGT("Сбой автоподбора! Температура повышена.");
   LSTR MSG_PID_TIMEOUT                      = _UxGT("Сбой автоподбора! Завершение времени.");
 
diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h
index 812e2a03c53..323ae684d5e 100644
--- a/Marlin/src/lcd/language/language_sk.h
+++ b/Marlin/src/lcd/language/language_sk.h
@@ -354,10 +354,10 @@ namespace Language_sk {
   LSTR MSG_PID_CYCLE                      = _UxGT("Cykly PID");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("Kal. PID dokončená");
   LSTR MSG_PID_AUTOTUNE_FAILED            = _UxGT("Kal. PID zlyhala!");
-  LSTR MSG_BAD_EXTRUDER_NUM               = _UxGT("Zlý extrudér");
+  LSTR MSG_BAD_HEATER_ID                  = _UxGT("Zlý extrudér");
   LSTR MSG_TEMP_TOO_HIGH                  = _UxGT("Príliš vysoká tepl.");
   LSTR MSG_TIMEOUT                        = _UxGT("Čas vypršal.");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Auto-kal. zlyhala! Zlý extrúder.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Auto-kal. zlyhala! Zlý extrúder.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Auto-kal. zlyhala! Príliš vysoká tepl.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Auto-kal. zlyhala! Čas vypršal.");
   LSTR MSG_MPC_MEASURING_AMBIENT          = _UxGT("Test. tepl. straty");
diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h
index 7b3c2d56a66..a18691fe0e5 100644
--- a/Marlin/src/lcd/language/language_sv.h
+++ b/Marlin/src/lcd/language/language_sv.h
@@ -291,7 +291,7 @@ namespace Language_sv {
   LSTR MSG_PID_AUTOTUNE                   = _UxGT("PID Autojustera");
   LSTR MSG_PID_AUTOTUNE_E                 = _UxGT("PID Autojustera *");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("PID tuning done");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("Autojustera misslyckad! Dålig extruder.");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("Autojustera misslyckad! Dålig extruder.");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("Autojustera misslyckad! Temperatur för hög.");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("Autojustera misslyckad! Tidsgräns.");
   LSTR MSG_SELECT_E                       = _UxGT("Välj *");
diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h
index 59dd14812b7..697445288db 100644
--- a/Marlin/src/lcd/language/language_uk.h
+++ b/Marlin/src/lcd/language/language_uk.h
@@ -387,7 +387,7 @@ namespace Language_uk {
   LSTR MSG_PID_AUTOTUNE                     = _UxGT("Автопідбір PID");
   LSTR MSG_PID_AUTOTUNE_E                   = _UxGT("Автопідбір PID *");
   LSTR MSG_PID_AUTOTUNE_DONE                = _UxGT("Підбір PID виконано");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM             = _UxGT("Збій автопідбору! Поганий екструдер.");
+  LSTR MSG_PID_BAD_HEATER_ID                = _UxGT("Збій автопідбору! Поганий екструдер.");
   LSTR MSG_PID_TEMP_TOO_HIGH                = _UxGT("Збій автопідбору! Температура завищена.");
   LSTR MSG_PID_TIMEOUT                      = _UxGT("Збій автопідбору! Вичерпан час.");
 
diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h
index 26515b60940..79c59be44b0 100644
--- a/Marlin/src/lcd/language/language_zh_CN.h
+++ b/Marlin/src/lcd/language/language_zh_CN.h
@@ -261,7 +261,7 @@ namespace Language_zh_CN {
   LSTR MSG_PID_AUTOTUNE                   = _UxGT("自动PID");
   LSTR MSG_PID_AUTOTUNE_E                 = _UxGT("自动PID *");
   LSTR MSG_PID_AUTOTUNE_DONE              = _UxGT("PID调整完成");
-  LSTR MSG_PID_BAD_EXTRUDER_NUM           = _UxGT("自动调失败! 坏的挤出机");
+  LSTR MSG_PID_BAD_HEATER_ID              = _UxGT("自动调失败! 坏的挤出机");
   LSTR MSG_PID_TEMP_TOO_HIGH              = _UxGT("自动调失败! 温度太高");
   LSTR MSG_PID_TIMEOUT                    = _UxGT("自动调失败! 超时");
   LSTR MSG_SELECT_E                       = _UxGT("选择 *");
diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp
index 8e1963afe59..6f404f20e11 100644
--- a/Marlin/src/lcd/menu/menu_advanced.cpp
+++ b/Marlin/src/lcd/menu/menu_advanced.cpp
@@ -41,7 +41,7 @@
   #include "../../module/probe.h"
 #endif
 
-#if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER)
+#if HAS_PID_HEATING
   #include "../../module/temperature.h"
 #endif
 
@@ -277,10 +277,10 @@ void menu_backlash();
 //
 #if SHOW_MENU_ADVANCED_TEMPERATURE
 
-  #if ENABLED(MPC_EDIT_MENU)
-    #define MPC_EDIT_DEFS(N) \
-      MPC_t &c = thermalManager.temp_hotend[N].constants; \
-      TERN_(MPC_INCLUDE_FAN, editable.decimal = c.ambient_xfer_coeff_fan0 + c.fan255_adjustment)
+  #if BOTH(MPC_EDIT_MENU, MPC_INCLUDE_FAN)
+    #define MPC_EDIT_DEFS(N) editable.decimal = thermalManager.temp_hotend[N].fanCoefficient()
+  #else
+    #define MPC_EDIT_DEFS(...)
   #endif
 
   void menu_advanced_temperature() {
@@ -370,17 +370,17 @@ void menu_backlash();
     #if ENABLED(MPC_EDIT_MENU)
 
       #define _MPC_EDIT_ITEMS(N) \
-        EDIT_ITEM_FAST_N(float31sign, N, MSG_MPC_POWER_E, &c.heater_power, 1, 200); \
-        EDIT_ITEM_FAST_N(float31sign, N, MSG_MPC_BLOCK_HEAT_CAPACITY_E, &c.block_heat_capacity, 0, 40); \
-        EDIT_ITEM_FAST_N(float43, N, MSG_SENSOR_RESPONSIVENESS_E, &c.sensor_responsiveness, 0, 1); \
-        EDIT_ITEM_FAST_N(float43, N, MSG_MPC_AMBIENT_XFER_COEFF_E, &c.ambient_xfer_coeff_fan0, 0, 1)
+        EDIT_ITEM_FAST_N(float31sign, N, MSG_MPC_POWER_E, &mpc.heater_power, 1, 200); \
+        EDIT_ITEM_FAST_N(float31sign, N, MSG_MPC_BLOCK_HEAT_CAPACITY_E, &mpc.block_heat_capacity, 0, 40); \
+        EDIT_ITEM_FAST_N(float43, N, MSG_SENSOR_RESPONSIVENESS_E, &mpc.sensor_responsiveness, 0, 1); \
+        EDIT_ITEM_FAST_N(float43, N, MSG_MPC_AMBIENT_XFER_COEFF_E, &mpc.ambient_xfer_coeff_fan0, 0, 1)
 
       #if ENABLED(MPC_INCLUDE_FAN)
         #define MPC_EDIT_ITEMS(N) \
+          MPC_t &mpc = thermalManager.temp_hotend[MenuItemBase::itemIndex].constants; \
           _MPC_EDIT_ITEMS(N); \
           EDIT_ITEM_FAST_N(float43, N, MSG_MPC_AMBIENT_XFER_COEFF_FAN_E, &editable.decimal, 0, 1, []{ \
-            MPC_t &c = thermalManager.temp_hotend[MenuItemBase::itemIndex].constants; \
-            c.fan255_adjustment = editable.decimal - c.ambient_xfer_coeff_fan0; \
+            thermalManager.temp_hotend[MenuItemBase::itemIndex].applyFanAdjustment(editable.decimal); \
           })
       #else
         #define MPC_EDIT_ITEMS _MPC_EDIT_ITEMS
diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp
index afdbf3d1034..8b615f2faf1 100644
--- a/Marlin/src/module/settings.cpp
+++ b/Marlin/src/module/settings.cpp
@@ -1632,8 +1632,7 @@ void MarlinSettings::postprocess() {
     // Model predictive control
     //
     #if ENABLED(MPCTEMP)
-      HOTEND_LOOP()
-        EEPROM_WRITE(thermalManager.temp_hotend[e].constants);
+      HOTEND_LOOP() EEPROM_WRITE(thermalManager.temp_hotend[e].mpc);
     #endif
 
     //
@@ -2627,8 +2626,7 @@ void MarlinSettings::postprocess() {
       //
       #if ENABLED(MPCTEMP)
       {
-        HOTEND_LOOP()
-          EEPROM_READ(thermalManager.temp_hotend[e].constants);
+        HOTEND_LOOP() EEPROM_READ(thermalManager.temp_hotend[e].mpc);
       }
       #endif
 
@@ -3416,15 +3414,15 @@ void MarlinSettings::reset() {
     static_assert(COUNT(_filament_heat_capacity_permm) == HOTENDS, "FILAMENT_HEAT_CAPACITY_PERMM must have HOTENDS items.");
 
     HOTEND_LOOP() {
-      MPC_t &constants = thermalManager.temp_hotend[e].constants;
-      constants.heater_power = _mpc_heater_power[e];
-      constants.block_heat_capacity = _mpc_block_heat_capacity[e];
-      constants.sensor_responsiveness = _mpc_sensor_responsiveness[e];
-      constants.ambient_xfer_coeff_fan0 = _mpc_ambient_xfer_coeff[e];
+      MPC_t &mpc = thermalManager.temp_hotend[e].mpc;
+      mpc.heater_power = _mpc_heater_power[e];
+      mpc.block_heat_capacity = _mpc_block_heat_capacity[e];
+      mpc.sensor_responsiveness = _mpc_sensor_responsiveness[e];
+      mpc.ambient_xfer_coeff_fan0 = _mpc_ambient_xfer_coeff[e];
       #if ENABLED(MPC_INCLUDE_FAN)
-        constants.fan255_adjustment = _mpc_ambient_xfer_coeff_fan255[e] - _mpc_ambient_xfer_coeff[e];
+        mpc.fan255_adjustment = _mpc_ambient_xfer_coeff_fan255[e] - _mpc_ambient_xfer_coeff[e];
       #endif
-      constants.filament_heat_capacity_permm = _filament_heat_capacity_permm[e];
+      mpc.filament_heat_capacity_permm = _filament_heat_capacity_permm[e];
     }
   #endif
 
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index c53fa5df14e..a4f528a4c81 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -660,13 +660,13 @@ volatile bool Temperature::raw_temps_ready = false;
     TERN_(HAS_FAN_LOGIC, fan_update_ms = next_temp_ms + fan_update_interval_ms);
 
     TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_STARTED));
-    TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(isbed ? PIDTEMPBED_START : PIDTEMP_START));
+    TERN_(DWIN_PID_TUNE, DWIN_PidTuning(isbed ? PIDTEMPBED_START : PIDTEMP_START));
 
     if (target > GHV(CHAMBER_MAX_TARGET, BED_MAX_TARGET, temp_range[heater_id].maxtemp - (HOTEND_OVERSHOOT))) {
       SERIAL_ECHOPGM(STR_PID_AUTOTUNE);
       SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH);
       TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH));
-      TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TEMP_TOO_HIGH));
+      TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_TEMP_TOO_HIGH));
       TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH)));
       return;
     }
@@ -760,7 +760,7 @@ volatile bool Temperature::raw_temps_ready = false;
         SERIAL_ECHOPGM(STR_PID_AUTOTUNE);
         SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH);
         TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH));
-        TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TEMP_TOO_HIGH));
+        TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_TEMP_TOO_HIGH));
         TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH)));
         break;
       }
@@ -797,7 +797,7 @@ volatile bool Temperature::raw_temps_ready = false;
       #endif
       if ((ms - _MIN(t1, t2)) > (MAX_CYCLE_TIME_PID_AUTOTUNE * 60L * 1000L)) {
         TERN_(DWIN_CREALITY_LCD, DWIN_Popup_Temperature(0));
-        TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_TUNING_TIMEOUT));
+        TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_TUNING_TIMEOUT));
         TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TUNING_TIMEOUT));
         TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TIMEOUT)));
         SERIAL_ECHOPGM(STR_PID_AUTOTUNE);
@@ -852,7 +852,7 @@ volatile bool Temperature::raw_temps_ready = false;
         TERN_(PRINTER_EVENT_LEDS, printerEventLEDs.onPidTuningDone(color));
 
         TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_DONE));
-        TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_DONE));
+        TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_DONE));
 
         goto EXIT_M303;
       }
@@ -870,7 +870,7 @@ volatile bool Temperature::raw_temps_ready = false;
     TERN_(PRINTER_EVENT_LEDS, printerEventLEDs.onPidTuningDone(color));
 
     TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_DONE));
-    TERN_(DWIN_LCD_PROUI, DWIN_PidTuning(PID_DONE));
+    TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_DONE));
 
     EXIT_M303:
       TERN_(NO_FAN_SLOWING_IN_PID_TUNING, adaptive_fan_slowing = true);
@@ -882,7 +882,7 @@ volatile bool Temperature::raw_temps_ready = false;
 #if ENABLED(MPCTEMP)
 
   void Temperature::MPC_autotune() {
-    auto housekeeping = [] (millis_t& ms, celsius_float_t& current_temp, millis_t& next_report_ms) {
+    auto housekeeping = [] (millis_t &ms, celsius_float_t &current_temp, millis_t &next_report_ms) {
       ms = millis();
 
       if (updateTemperaturesIfReady()) { // temp sample ready
@@ -929,7 +929,7 @@ volatile bool Temperature::raw_temps_ready = false;
     SERIAL_ECHOPGM(STR_MPC_AUTOTUNE);
     SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, active_extruder);
     MPCHeaterInfo &hotend = temp_hotend[active_extruder];
-    MPC_t &constants = hotend.constants;
+    MPC_t &mpc = hotend.mpc;
 
     // Move to center of bed, just above bed height and cool with max fan
     gcode.home_all_axes(true);
@@ -939,11 +939,11 @@ volatile bool Temperature::raw_temps_ready = false;
       set_fan_speed(EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255);
       planner.sync_fan_speeds(fan_speed);
     #endif
-    const xyz_pos_t tuningpos = MPC_TUNING_POS;
-    do_blocking_move_to(tuningpos);
+    do_blocking_move_to(xyz_pos_t(MPC_TUNING_POS));
 
     SERIAL_ECHOLNPGM(STR_MPC_COOLING_TO_AMBIENT);
     LCD_MESSAGE(MSG_COOLING);
+
     millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL;
     celsius_float_t current_temp = degHotend(active_extruder),
                     ambient_temp = current_temp;
@@ -961,6 +961,7 @@ volatile bool Temperature::raw_temps_ready = false;
         next_test_ms += 10000UL;
       }
     }
+    wait_for_heatup = false;
 
     #if HAS_FAN
       set_fan_speed(EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 0);
@@ -970,7 +971,7 @@ volatile bool Temperature::raw_temps_ready = false;
     hotend.modeled_ambient_temp = ambient_temp;
 
     SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200);
-    LCD_MESSAGE(MSG_HEATING);
+    TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING));
     hotend.target = 200.0f;   // So M105 looks nice
     hotend.soft_pwm_amount = MPC_MAX >> 1;
     const millis_t heat_start_time = next_test_ms = ms;
@@ -1012,17 +1013,17 @@ volatile bool Temperature::raw_temps_ready = false;
     float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3),
           block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1));
 
-    constants.ambient_xfer_coeff_fan0 = constants.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp);
-    constants.fan255_adjustment = 0.0f;
-    constants.block_heat_capacity = constants.ambient_xfer_coeff_fan0 / block_responsiveness;
-    constants.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp));
+    mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp);
+    mpc.fan255_adjustment = 0.0f;
+    mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness;
+    mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp));
 
     hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f);
     hotend.modeled_sensor_temp = current_temp;
 
     // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan
     SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp);
-    LCD_MESSAGE(MSG_MPC_MEASURING_AMBIENT);
+    TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_MEASURING_AMBIENT), LCD_MESSAGE(MSG_MPC_MEASURING_AMBIENT));
     hotend.target = hotend.modeled_block_temp;
     next_test_ms = ms + MPC_dT * 1000;
     constexpr millis_t settle_time = 20000UL, test_duration = 20000UL;
@@ -1042,7 +1043,7 @@ volatile bool Temperature::raw_temps_ready = false;
         hotend.soft_pwm_amount = (int)get_pid_output_hotend(active_extruder) >> 1;
 
         if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done))
-          total_energy_fan0 += constants.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * constants.block_heat_capacity;
+          total_energy_fan0 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity;
         #if HAS_FAN
           else if (ELAPSED(ms, test_end_ms) && !fan0_done) {
             set_fan_speed(EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) ? 0 : active_extruder, 255);
@@ -1052,7 +1053,7 @@ volatile bool Temperature::raw_temps_ready = false;
             fan0_done = true;
           }
           else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms))
-            total_energy_fan255 += constants.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * constants.block_heat_capacity;
+            total_energy_fan255 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity;
         #endif
         else if (ELAPSED(ms, test_end_ms)) break;
 
@@ -1067,24 +1068,24 @@ volatile bool Temperature::raw_temps_ready = false;
     }
 
     const float power_fan0 = total_energy_fan0 * 1000 / test_duration;
-    constants.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp);
+    mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp);
 
     #if HAS_FAN
       const float power_fan255 = total_energy_fan255 * 1000 / test_duration,
                   ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp);
-      constants.fan255_adjustment = ambient_xfer_coeff_fan255 - constants.ambient_xfer_coeff_fan0;
+      mpc.applyFanAdjustment(ambient_xfer_coeff_fan255);
     #endif
 
     // Calculate a new and better asymptotic temperature and re-evaluate the other constants
-    asymp_temp = ambient_temp + constants.heater_power * (MPC_MAX) / 255 / constants.ambient_xfer_coeff_fan0;
+    asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0;
     block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1));
-    constants.block_heat_capacity = constants.ambient_xfer_coeff_fan0 / block_responsiveness;
-    constants.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp));
+    mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness;
+    mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp));
 
     SERIAL_ECHOPGM(STR_MPC_AUTOTUNE);
     SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED);
 
-    /* <-- add a slash to enable
+    #if 0
       SERIAL_ECHOLNPGM("t1_time ", t1_time);
       SERIAL_ECHOLNPGM("sample_count ", sample_count);
       SERIAL_ECHOLNPGM("sample_distance ", sample_distance);
@@ -1093,10 +1094,11 @@ volatile bool Temperature::raw_temps_ready = false;
       SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3);
       SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp);
       SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4);
-    //*/
-    SERIAL_ECHOLNPGM("MPC_BLOCK_HEAT_CAPACITY ", constants.block_heat_capacity);
-    SERIAL_ECHOLNPAIR_F("MPC_SENSOR_RESPONSIVENESS ", constants.sensor_responsiveness, 4);
-    SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF ", constants.ambient_xfer_coeff_fan0, 4);
+    #endif
+
+    SERIAL_ECHOLNPGM("MPC_BLOCK_HEAT_CAPACITY ", mpc.block_heat_capacity);
+    SERIAL_ECHOLNPAIR_F("MPC_SENSOR_RESPONSIVENESS ", mpc.sensor_responsiveness, 4);
+    SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF ", mpc.ambient_xfer_coeff_fan0, 4);
     TERN_(HAS_FAN, SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF_FAN255 ", ambient_xfer_coeff_fan255, 4));
   }
 
@@ -1413,7 +1415,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id) {
     #elif ENABLED(MPCTEMP)
 
       MPCHeaterInfo &hotend = temp_hotend[ee];
-      MPC_t &constants = hotend.constants;
+      MPC_t &mpc = hotend.mpc;
 
       // At startup, initialize modeled temperatures
       if (isnan(hotend.modeled_block_temp)) {
@@ -1427,11 +1429,11 @@ void Temperature::mintemp_error(const heater_id_t heater_id) {
         const bool this_hotend = (ee == active_extruder);
       #endif
 
-      float ambient_xfer_coeff = constants.ambient_xfer_coeff_fan0;
+      float ambient_xfer_coeff = mpc.ambient_xfer_coeff_fan0;
       #if ENABLED(MPC_INCLUDE_FAN)
         const uint8_t fan_index = EITHER(MPC_FAN_0_ACTIVE_HOTEND, MPC_FAN_0_ALL_HOTENDS) ? 0 : ee;
         const float fan_fraction = TERN_(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend ? 0.0f : ) fan_speed[fan_index] * RECIPROCAL(255);
-        ambient_xfer_coeff += fan_fraction * constants.fan255_adjustment;
+        ambient_xfer_coeff += fan_fraction * mpc.fan255_adjustment;
       #endif
 
       if (this_hotend) {
@@ -1442,17 +1444,17 @@ void Temperature::mintemp_error(const heater_id_t heater_id) {
         if (fabs(e_speed) > planner.settings.max_feedrate_mm_s[E_AXIS])
           mpc_e_position = e_position;
         else if (e_speed > 0.0f) {  // Ignore retract/recover moves
-          ambient_xfer_coeff += e_speed * constants.filament_heat_capacity_permm;
+          ambient_xfer_coeff += e_speed * mpc.filament_heat_capacity_permm;
           mpc_e_position = e_position;
         }
       }
 
       // Update the modeled temperatures
-      float blocktempdelta = hotend.soft_pwm_amount * constants.heater_power * (MPC_dT / 127) / constants.block_heat_capacity;
-      blocktempdelta += (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff * MPC_dT / constants.block_heat_capacity;
+      float blocktempdelta = hotend.soft_pwm_amount * mpc.heater_power * (MPC_dT / 127) / mpc.block_heat_capacity;
+      blocktempdelta += (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff * MPC_dT / mpc.block_heat_capacity;
       hotend.modeled_block_temp += blocktempdelta;
 
-      const float sensortempdelta = (hotend.modeled_block_temp - hotend.modeled_sensor_temp) * (constants.sensor_responsiveness * MPC_dT);
+      const float sensortempdelta = (hotend.modeled_block_temp - hotend.modeled_sensor_temp) * (mpc.sensor_responsiveness * MPC_dT);
       hotend.modeled_sensor_temp += sensortempdelta;
 
       // Any delta between hotend.modeled_sensor_temp and hotend.celsius is either model
@@ -1468,11 +1470,11 @@ void Temperature::mintemp_error(const heater_id_t heater_id) {
       float power = 0.0;
       if (hotend.target != 0 && !is_idling) {
         // Plan power level to get to target temperature in 2 seconds
-        power = (hotend.target - hotend.modeled_block_temp) * constants.block_heat_capacity / 2.0f;
+        power = (hotend.target - hotend.modeled_block_temp) * mpc.block_heat_capacity / 2.0f;
         power -= (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff;
       }
 
-      float pid_output = power * 254.0f / constants.heater_power + 1.0f;        // Ensure correct quantization into a range of 0 to 127
+      float pid_output = power * 254.0f / mpc.heater_power + 1.0f;        // Ensure correct quantization into a range of 0 to 127
       pid_output = constrain(pid_output, 0, MPC_MAX);
 
       /* <-- add a slash to enable
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index d099c3d73b3..0b5f8caf3fa 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -382,10 +382,14 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t;
     float block_heat_capacity;          // M306 C
     float sensor_responsiveness;        // M306 R
     float ambient_xfer_coeff_fan0;      // M306 A
+    float filament_heat_capacity_permm; // M306 H
     #if ENABLED(MPC_INCLUDE_FAN)
       float fan255_adjustment;          // M306 F
+      void applyFanAdjustment(const_float_t cf) { fan255_adjustment = cf - ambient_xfer_coeff_fan0; }
+    #else
+      void applyFanAdjustment(const_float_t) {}
     #endif
-    float filament_heat_capacity_permm; // M306 H
+    float fanCoefficient() { return SUM_TERN(MPC_INCLUDE_FAN, ambient_xfer_coeff_fan0, fan255_adjustment); }
   } MPC_t;
 
   #define MPC_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (TEMP_TIMER_FREQUENCY))
@@ -433,10 +437,12 @@ struct PIDHeaterInfo : public HeaterInfo {
 
 #if ENABLED(MPCTEMP)
   struct MPCHeaterInfo : public HeaterInfo {
-    MPC_t constants;
+    MPC_t mpc;
     float modeled_ambient_temp,
           modeled_block_temp,
           modeled_sensor_temp;
+    float fanCoefficient() { return mpc.fanCoefficient(); }
+    void applyFanAdjustment(const_float_t cf) { mpc.applyFanAdjustment(cf); }
   };
 #endif