Close

Ramp up and down

A project log for Ventbot: warm side cool, cool side warm

A DIY register booster project to even out the temps around my home.

wjcarpenterWJCarpenter 11/20/2022 at 21:400 Comments

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:

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