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