The ThermalCollector is the central module in tlBMC responsible for managing thermal zones, executing fan and thermal control loops, and coordinating controllers to maintain platform temperatures.
The ThermalCollector orchestrates the system's active cooling by instantiating and running ZoneManager instances for each defined thermal zone. It reads telemetry from various sensor types (including temperature, fan speed, power for DFF feedforward control, and current sensors), computes setpoints via various controller algorithms (PID, Stepwise, DFF, EAT), and writes target speed/PWM values to fan speed controllers.
When enabled, the ThermalCollector owns the following Redfish endpoints:
/redfish/v1/Chassis/<ChassisId>/ThermalSubsystem and its /Fans/redfish/v1/Chassis/<ChassisId>/PowerSubsystem and its /PowerSupplies/redfish/v1/Managers/<ManagerId> (Oem OpenBmc Fan endpoints)/redfish/v1/Managers/bmc/Actions/Manager.FanMode.Change (POST)/redfish/v1/Managers/bmc/FanMode.Change.ActionInfo/redfish/v1/Chassis/<ChassisId>/Sensors (PATCH for setpoint overrides)[!NOTE] When the
ThermalCollectoris active, it removes the legacy/redfish/v1/Chassis/<ChassisId>/Thermalendpoint.
If the thermal control submodule is disabled, tlBMC instantiates the EmptyThermalCollector. This is a no-op fallback implementation that exposes placeholder metrics and returns warning payloads indicating that thermal collection is disabled (e.g., "Warning": "EmptyThermalCollector used." in debug store endpoints).
The thermal collector is configured as a submodule of the sensor collector in the central configuration file.
Declared in central_config.proto under the SensorCollectorModule:
message ThermalControlSubmodule { bool enabled = 1 [default = false]; }
| Field Name | Type | Default Value | Description |
|---|---|---|---|
enabled | bool | false | When true, enables |
| : : : : the : | |||
: : : : ThermalCollector : | |||
| : : : : and activates the : | |||
| : : : : thermal control : | |||
| : : : : loops. : |
Platform integrators configure physical fan hardware and logical fan resources in the Entity Manager JSON configuration files.
The JSON config maps keys with TlbmcOwned set to true into the store:
I2CFan: Defines hardware-level fan tachometer properties and default controller addresses.Fan: Exposes the high-level physical fan unit linking PWM outputs and tachometer inputs.MAX31790: Defines the hardware fan controller chip characteristics.The properties for the high-level Fan configuration entry:
| Parameter Name | Expected Type | Description |
|---|---|---|
Type | string | Must be "Fan". |
Name | string | Unique name of the fan (e.g., |
: : : "fan0_rear_tach"). : | ||
LocationType | string | Redfish physical location type (e.g., |
: : : "Connector"). : | ||
ServiceLabel | string | Silkscreen or service label identifying the |
| : : : fan slot. : | ||
HotPluggable | bool | Whether the fan supports hot-swapping. |
PWMSensor | string | The associated PWM sensor name (e.g., |
: : : "fan0_pwm"). : | ||
TachSensor | string | The associated Tachometer sensor name |
: : : (e.g., "fan0_rear_tach"). : | ||
Model | string | (Optional) Fan model identifier (e.g., |
: : : "fan_92mm"). : |
Below is a mocked Entity Manager JSON extract showing how fans and fan controllers are defined:
[ { "Address": "0x2c", "Bus": "96", "Connector": { "DefaultPwm": 50, "Mutable": true, "Name": "fan0_rear_tach", "Pwm": 0, "PwmName": "fan0_pwm", "Tachs": [ 0 ] }, "Index": 0, "MaxReading": 19800, "Name": "fan0_rear_tach", "TlbmcOwned": true, "PowerState": "Always", "RelatedItem": { "Id": "Fan0", "Type": "RESOURCE_TYPE_FAN", "User": "tlbmc" }, "Type": "I2CFan" }, { "HotPluggable": false, "LocationType": "Connector", "Model": "fan_92mm", "Name": "fan0_rear_tach", "PWMSensor": "fan0_pwm", "ServiceLabel": "FAN0_rear", "TachSensor": "fan0_rear_tach", "Type": "Fan", "TlbmcOwned": true }, { "Address": "0x2c", "Bus": "96", "Name": "FAN_CONTROLLER_U19", "Type": "MAX31790", "TlbmcOwned": true } ]
The control loops, thermal zones, and controllers are structured in thermal_config.proto.
Key submessages parsed into ThermalConfigs:
Defines the attributes and timing limits of a thermal zone:
| Field Name | Type | Default Value | Description |
|---|---|---|---|
id | int32 | - | Unique ID of the |
| : : : : zone. : | |||
setpoint_upper_bound | double | - | Upper bound for |
| : : : : calculated thermal : | |||
| : : : : setpoints. : | |||
setpoint_lower_bound | double | - | Lower bound for |
| : : : : calculated thermal : | |||
| : : : : setpoints. : | |||
minimum_thermal_setpoint | double | - | Hard-minimum |
| : : : : thermal setpoint : | |||
| : : : : value allowed. : | |||
zone_failsafe_percent | double | 100 | PWM output |
| : : : : percentage written : | |||
| : : : : during zone : | |||
| : : : : failsafe mode. : | |||
ms_per_fan_cycle | uint64 | 100 | Timing interval |
| : : : : (ms) between fan : | |||
| : : : : speed evaluations. : | |||
ms_per_thermal_cycle | uint64 | 1000 | Timing interval |
| : : : : (ms) between : | |||
| : : : : thermal controller : | |||
| : : : : evaluations. : | |||
input_sensors | repeated | - | Sensor inputs |
| : : : : monitored by this : | |||
| : : : : zone. : | |||
output_fans | repeated | - | Fan outputs driven |
| : : : : by this zone. : |
Sets parameters for a standard PID (Proportional-Integral-Derivative) control loop:
| Field Name | Type | Description |
|---|---|---|
id | string | Unique ID of the controller. |
zone_manager_id | repeated int32 | IDs of the zones this controller |
| : : : belongs to. : | ||
setpoint | double | Target temperature/margin value. |
input_process_type | enum | Type of process input (TEMP_PID, |
: : : MARGIN_PID, POWER_PID, etc.). : | ||
pid_loop_config | PidLoopConfig | Contains coefficients |
: : : (coeff_proportional, : | ||
: : : coeff_integral, : | ||
: : : coeff_derivative, : | ||
: : : feed_forward_gain, offsets, : | ||
| : : : etc.). : |
The main control loop runs asynchronously in ProcessThermalControl using boost::asio::steady_timer structures.
ms_per_fan_cycle): Executed every cycle (typically 100ms). Fan sensors are updated, fan PID controllers are processed, and target speeds are written to hardware registers.ms_per_thermal_cycle): Executed periodically (typically every 1000ms). Invokes ProcessOneThermalLoop to update temperature sensors, run PID/Stepwise controllers, and compute zone setpoints.max_threshold_critical / min_threshold_critical), the zone triggers Failsafe Mode, locking the fans to the configured zone_failsafe_percent (or individual failsafe_percent).tlBMC provides interfaces to inspect and tune controller behavior at runtime via Redfish actions.
To toggle manual fan speed control, make a POST request to the Manager action:
URL: /redfish/v1/Managers/bmc/Actions/Manager.FanMode.Change
Payload:
{ "FanMode": "Manual" }
(Set FanMode to "Auto" to return control to the active loops).
Integrators can tune PID coefficients and setpoints on-the-fly by issuing a PATCH request to the Manager endpoint:
URL: /redfish/v1/Managers/bmc
Payload:
{ "Oem": { "OpenBmc": { "Fan": { "PidControllers": { "TEMP_PID_0": { "PCoefficient": -3.5, "ICoefficient": -0.15, "DCoefficient": 0.0, "FFGainCoefficient": 1.0, "SetPoint": 90.0 } }, "FanControllers": { "FAN_CTRL_01": { "PCoefficient": 0.1, "FFGainCoefficient": 1.2 } } } } } }
[!TIP] The coefficients map to
coeff_proportional,coeff_integral,coeff_derivative,feed_forward_gain, andsetpointin the PID implementation. They are queued and thread-safely applied viaApplyPendingTuningRequestsat the start of the next control cycle.
ThermalCollector: Instantiates and manages all thermal zones, schedules tasks, and coordinates tuning threads.ZoneManager: Orchestrates a single zone's loop, maintains sensor values, processes controllers, and writes outputs.PidController: Implements standard Proportional-Integral-Derivative math for temperature and power regulation.StepwiseController: Evaluates step-based lookup tables (e.g., temperatures mapping to discrete fan speed values).FanPidController: Regulates fan RPM speeds based on target PWM inputs.DffController: Performs Dynamic Feedforward calculations to pre-emptively adjust cooling when workload power changes.EatController: Handles Entering Air Temperature calculations.ThermalCollector and EmptyThermalCollector.