I plan to have a configurable way to spin the fans up and down when needed. When I say configurable, I currently don't have in mind anything fancier than editing some tabular data in the ESPHome configuration file. Maybe someday that table will be stored in ESP32 preferences storage so it can be modified without rebuilding the firmware. That's a bigger adventure than I am thinking about at the moment. I'm imagining the ESPHome configuration file being edited by someone who is not necessarily technically sophisticated. So, I don't want them to have to dig around too much in the file or have to deal with syntax that is too complex.
Here is what I have right now:
- The ramp consists of any number of steps. Presumably, they start with low speeds and move increasingly upwards, but that is not enforced.
- There's a kind of implied first step, which is "everything is off".
- Each step consists of a duration (I'm not sure yet if it will be in seconds or milliseconds) and a set of PWM duty cycle percentages. The meaning is "set the fans to the specified PWM duty cycle values and wait for the duration time before moving to the next step".
- The duration for the final step is ignored (or treated as "infinity") since there is nothing to wait for. The fans will continue at those settings until it's time to ramp down.
- For ramp down, the steps are used in the reverse order. The highest-numbered step will ordinarily be where the ramp up left us. For ramp down, the duration of that step is taken as 0.
I'm not completely sure the ramp up and ramp down behavior should be symmetric. I'm doing that for simplicity but may have to add more complexity to it later.
ESPHome has a feature for defining global variables. Theoretically, the ramp up and ramp down could be done completely using the table defined in global variables and ESPHome primitives. It's rather inconvenient to do that for more than a few simple variables, and I think it would obscure the logic of the simple table I'm using. I'm planning to use an ESPHome lambda block to do the ramp up and ramp down in C++.
To avoid the need to naive users to grovel around in C++ code located deep in the ESPHome configuration file, I'm using the ESPHome substitutions feature to define the guts of the table up near the top of the ESPHome configuration file. That fragment is then plugged into some C++ code in an ESPHome lambda later. It's a purely mechanical substitution. Here is an example of the table. The numbers in this example are not sensible and were chosen just to be sure of what's going on in debug logging.
substitutions:
RAMP_TABLE: |-
{1, {11, 12, 13, 14}},
{2, {21, 22, 23}},
{3, {31, 32}},
{4, {41}},
The syntax here is not too onerous, and I think the average person can handle it.
It's still possible to get it wrong. When you're trying to do a static initialization of an array of structs in C++, it's like trying to get help from a lawyer with whom you do not share a common language. You say what you think you want, and they respond with a load of gibberish. There are a few words in there that you recognize, but the sequence of words makes no sense and is not helpful. With the aid of some web searches, you eventually get something that does not bring forth a string of complaints from them, but you're not sure what you asked for is what you want. (I spent a lot of years doing development in C. I was at Bell Labs when C++ came along. For a while, the motto was "a better C", but it eventually changed to "a better C, plus a couple of train wrecks thrown in for free".)
Here is some ESPHome lambda code that prints out the ramp table. You can see the ${RAMP_TABLE} value substituted at around line 7. ${FAN_COUNT} is another ESPHome substitution and has the value 4 (for the maximum possible fans, not necessarily the number of actual fans).
- lambda: |-
typedef struct {
short duration;
short pwm[${FAN_COUNT}];
} RAMP_STEP;
static RAMP_STEP ramp_steps[] = {
${RAMP_TABLE}
};
static short number_of_ramp_steps = sizeof(ramp_steps) / sizeof(ramp_steps[0]);
static bool going_up;
going_up = !going_up;
ESP_LOGD("main", "There are %d ramp step", number_of_ramp_steps);
for (int ss=0; ss<number_of_ramp_steps; ++ss) {
RAMP_STEP *ramp_step = going_up ? &(ramp_steps[ss]) : &(ramp_steps[${FAN_COUNT} - ss - 1]);
ESP_LOGD("main", "%s step %d, dur %d", going_up?"UP ":"DOWN", ss, ramp_step->duration);
for (int ppu=0; ppu<${FAN_COUNT}; ++ppu) {
ESP_LOGD("main", " pwm %d", ramp_step->pwm[ppu]);
}
}
Missing values in the ramp table are initialized to 0. That's convenient for anyone who has fewer than 4 fans. I'm not sure yet what I will do during ramp up and ramp down when I see a 0 value. It might mean turn the fan off, or it might mean "don't change from the previous step's value". That's for another day.
Here's the ESPHome debug log output from the lambda block after one ramp up and one ramp down:
[13:37:31][D][main:077]: There are 4 ramp step
[13:37:31][D][main:080]: UP step 0, dur 1
[13:37:31][D][main:082]: pwm 11
[13:37:31][D][main:082]: pwm 12
[13:37:31][D][main:082]: pwm 13
[13:37:31][D][main:082]: pwm 14
[13:37:31][D][main:080]: UP step 1, dur 2
[13:37:31][D][main:082]: pwm 21
[13:37:31][D][main:082]: pwm 22
[13:37:31][D][main:082]: pwm 23
[13:37:31][D][main:082]: pwm 0
[13:37:31][D][main:080]: UP step 2, dur 3
[13:37:31][D][main:082]: pwm 31
[13:37:31][D][main:082]: pwm 32
[13:37:31][D][main:082]: pwm 0
[13:37:31][D][main:082]: pwm 0
[13:37:31][D][main:080]: UP step 3, dur 4
[13:37:31][D][main:082]: pwm 41
[13:37:31][D][main:082]: pwm 0
[13:37:31][D][main:082]: pwm 0
[13:37:31][D][main:082]: pwm 0
[13:37:36][D][main:077]: There are 4 ramp step
[13:37:36][D][main:080]: DOWN step 0, dur 4
[13:37:36][D][main:082]: pwm 41
[13:37:36][D][main:082]: pwm 0
[13:37:36][D][main:082]: pwm 0
[13:37:36][D][main:082]: pwm 0
[13:37:36][D][main:080]: DOWN step 1, dur 3
[13:37:36][D][main:082]: pwm 31
[13:37:36][D][main:082]: pwm 32
[13:37:36][D][main:082]: pwm 0
[13:37:36][D][main:082]: pwm 0
[13:37:36][D][main:080]: DOWN step 2, dur 2
[13:37:36][D][main:082]: pwm 21
[13:37:36][D][main:082]: pwm 22
[13:37:36][D][main:082]: pwm 23
[13:37:36][D][main:082]: pwm 0
[13:37:36][D][main:080]: DOWN step 3, dur 1
[13:37:36][D][main:082]: pwm 11
[13:37:36][D][main:082]: pwm 12
[13:37:36][D][main:082]: pwm 13
[13:37:36][D][main:082]: pwm 14
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.