1# How to Configure Phosphor-pid-control 2 3A system needs two groups of configurations: zones and sensors. 4 5## Json Configuration 6 7The json object should be a dictionary with two keys, `sensors` and `zones`. 8`sensors` is a list of the sensor dictionaries, whereas `zones` is a list of 9zones. 10 11### Sensors 12 13``` 14"sensors" : [ 15 { 16 "name": "fan1", 17 "type": "fan", 18 "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1", 19 "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm1", 20 "min": 0, 21 "max": 255, 22 "ignoreDbusMinMax": true 23 }, 24 { 25 "name": "fan2", 26 "type": "fan", 27 "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan2", 28 "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm2", 29 "min": 0, 30 "max": 255, 31 "timeout": 4, 32 }, 33... 34``` 35 36A sensor has a `name`, a `type`, a `readPath`, a `writePath`, a `minimum` value, 37a `maximum` value, a `timeout`, and a `ignoreDbusMinMax` value. 38 39The `name` is used to reference the sensor in the zone portion of the 40configuration. 41 42The `type` is the type of sensor it is. This influences how its value is 43treated. Supports values are: `fan`, `temp`, and `margin`. 44 45**TODO: Add further details on what the types mean.** 46 47The `readPath` is the path that tells the daemon how to read the value from this 48sensor. It is optional, allowing for write-only sensors. If the value is absent 49or `None` it'll be treated as a write-only sensor. 50 51If the `readPath` value contains: `/xyz/openbmc_project/extsensors/` it'll be 52treated as a sensor hosted by the daemon itself whose value is provided 53externally. The daemon will own the sensor and publish it to dbus. This is 54currently only supported for `temp` and `margin` sensor types. 55 56If the `readPath` value contains: `/xyz/openbmc_project/` (this is checked after 57external), then it's treated as a passive dbus sensor. A passive dbus sensor is 58one that listens for property updates to receive its value instead of actively 59reading the `Value` property. 60 61If the `readPath` value contains: `/sys/` this is treated as a directly read 62sysfs path. There are two supported paths: 63 64* `/sys/class/hwmon/hwmon0/pwm1` 65* `/sys/devices/platform/ahb/1e786000.pwm-tacho-controller/hwmon/<asterisk 66 asterisk>/pwm1` 67 68The `writePath` is the path to set the value for the sensor. This is only valid 69for a sensor of type `fan`. The path is optional. If can be empty or `None`. It 70then only supports two options. 71 72If the `writePath` value contains: `/sys/` this is treated as a directory 73written sysfs path. There are two support paths: 74 75* `/sys/class/hwmon/hwmon0/pwm1` 76* `/sys/devices/platform/ahb/1e786000.pwm-tacho-controller/hwmon/<asterisk 77 asterisk>/pwm1` 78 79If the `writePath` value contains: `/xyz/openbmc_project/sensors/fan_tach/fan{N}` it 80sets of a sensor object that writes over dbus to the 81`xyz.openbmc_project.Control.FanPwm` interface. The `writePath` should be the 82full object path. 83 84``` 85busctl introspect xyz.openbmc_project.Hwmon-1644477290.Hwmon1 /xyz/openbmc_project/sensors/fan_tach/fan1 --no-pager 86NAME TYPE SIGNATURE RESULT/VALUE FLAGS 87org.freedesktop.DBus.Introspectable interface - - - 88.Introspect method - s - 89org.freedesktop.DBus.Peer interface - - - 90.GetMachineId method - s - 91.Ping method - - - 92org.freedesktop.DBus.Properties interface - - - 93.Get method ss v - 94.GetAll method s a{sv} - 95.Set method ssv - - 96.PropertiesChanged signal sa{sv}as - - 97xyz.openbmc_project.Control.FanPwm interface - - - 98.Target property t 255 emits-change writable 99xyz.openbmc_project.Sensor.Value interface - - - 100.MaxValue property x 0 emits-change writable 101.MinValue property x 0 emits-change writable 102.Scale property x 0 emits-change writable 103.Unit property s "xyz.openbmc_project.Sensor.Value.Uni... emits-change writable 104.Value property x 2823 emits-change writable 105``` 106 107The `minimum` and `maximum` values are optional. When `maximum` is non-zero it 108expects to write a percentage value converted to a value between the minimum and 109maximum. 110 111The `timeout` value is optional and controls the sensor failure behavior. If a 112sensor is a fan the default value is 2 seconds, otherwise it's 0. When a 113sensor's timeout is 0 it isn't checked against a read timeout failure case. If a 114sensor fails to be read within the timeout period, the zone goes into failsafe 115to handle the case where it doesn't know what to do -- as it doesn't have all 116its inputs. 117 118The `ignoreDbusMinMax` value is optional and defaults to false. The dbus 119passive sensors check for a `MinValue` and `MaxValue` and scale the incoming 120values via these. Setting this property to true will ignore `MinValue` and 121`MaxValue` from dbus and therefore won't call any passive value scaling. 122 123### Zones 124 125``` 126"zones" : [ 127 { 128 "id": 1, 129 "minThermalOutput": 3000.0, 130 "failsafePercent": 75.0, 131 "pids": [], 132... 133``` 134 135Each zone has its own fields, and a list of PIDs. 136 137| field | type | meaning | 138| ------------------ | --------- | ----------------------------------------- | 139| `id` | `int64_t` | This is a unique identifier for the zone. | 140| `minThermalOutput` | `double` | This is the minimum value that should be considered from the thermal outputs. Commonly used as the minimum fan RPM.| 141| `failsafePercent` | `double` | If there is a fan PID, it will use this value if the zone goes into fail-safe as the output value written to the fan's sensors.| 142 143The `id` field here is used in the d-bus path to talk to the 144`xyz.openbmc_project.Control.Mode` interface. 145 146***TODO:*** Examine how the fan controller always treating its output as a 147percentage works for future cases. 148 149### PIDs 150 151There are a few PID types: `fan`, `temp`, `margin`, and `stepwise`. 152 153The `fan` PID is meant to drive fans. It's expecting to get the maximum RPM 154setpoint value from the owning zone and then drive the fans to that value. 155 156A `temp` PID is meant to drive the RPM setpoint given an absolute temperature 157value (higher value indicates a warmer temperature). 158 159A `margin` PID is meant to drive the RPM setpoint given a margin value (lower 160value indicates a warmer temperature). 161 162The setpoint output from the thermal controllers is called `RPMSetpoint()` 163However, it doesn't need to be an RPM value. 164 165***TODO:*** Rename this method and others to not say necessarily RPM. 166 167Some PID configurations have fields in common, but may be interpreted 168differently. 169 170#### PID Field 171 172If the PID `type` is not `stepwise` then the PID field is defined as follows: 173 174| field | type | meaning | 175| -------------------- | -------- | ----------------------------------------- | 176| `samplePeriod` | `double` | How frequently the value is sampled. 0.1 for fans, 1.0 for temperatures.| 177| `proportionalCoeff` | `double` | The proportional coefficient. | 178| `integralCoeff` | `double` | The integral coefficient. | 179| `feedFwdOffsetCoeff` | `double` | The feed forward offset coefficient. | 180| `feedFwdGainCoeff` | `double` | The feed forward gain coefficient. | 181| `integralLimit_min` | `double` | The integral minimum clamp value. | 182| `integralLimit_max` | `double` | The integral maximum clamp value. | 183| `outLim_min` | `double` | The output minimum clamp value. | 184| `outLim_max` | `double` | The output maximum clamp value. | 185| `slewNeg` | `double` | Negative slew value to dampen output. | 186| `slewPos` | `double` | Positive slew value to accelerate output. | 187 188The units for the coefficients depend on the configuration of the PIDs. 189 190If the PID is a `margin` controller and its `setpoint` is in centigrade and 191output in RPM: proportionalCoeff is your p value in units: RPM/C and integral 192coefficient: RPM/C sec 193 194If the PID is a fan controller whose output is pwm: proportionalCoeff is %/RPM 195and integralCoeff is %/RPM sec. 196 197***NOTE:*** The sample periods are specified in the configuration as they are 198used in the PID computations, however, they are not truly configurable as they 199are used for the update periods for the fan and thermal sensors. 200 201#### type == "fan" 202 203``` 204"name": "fan1-5", 205"type": "fan", 206"inputs": ["fan1", "fan5"], 207"setpoint": 90.0, 208"pid": { 209... 210} 211``` 212 213The type `fan` builds a `FanController` PID. 214 215| field | type | meaning | 216| ---------- | ----------------- | ------------------------------------------- | 217| `name` | `string` | The name of the PID. This is just for humans and logging.| 218| `type` | `string` | `fan` | 219| `inputs` | `list of strings` | The names of the sensor(s) that are used as input and output for the PID loop.| 220| `setpoint` | `double` | Presently UNUSED | 221| `pid` | `dictionary` | A PID dictionary detailed above. | 222 223#### type == "temp" 224 225***TODO:*** Add notes for temperature configuration. 226 227#### type == "margin" 228 229``` 230"name": "fleetingpid0", 231"type": "margin", 232"inputs": ["fleeting0"], 233"setpoint": 10, 234"pid": { 235... 236} 237``` 238 239The type `margin` builds a `ThermalController` PID. 240 241| field | type | meaning | 242| ---------- | ----------------- | ------------------------------------------- | 243| `name` | `string` | The name of the PID. This is just for humans and logging.| 244| `type` | `string` | `margin` | 245| `inputs` | `list of strings` | The names of the sensor(s) that are used as input for the PID loop.| 246| `setpoint` | `double` | The setpoint value for the thermal PID. The setpoint for the margin sensors.| 247| `pid` | `dictionary` | A PID dictionary detailed above. | 248 249The output of a `margin` PID loop is that it sets the setpoint value for the 250zone. It does this by adding the value to a list of values. The value chosen by 251the fan PIDs (in this cascade configuration) is the maximum value. 252 253#### type == "stepwise" 254 255***TODO:*** Write up `stepwise` details. 256