I spent years staring at cold chain data with exactly this pattern. Part of your coupling sits in the measured variable itself, because RH depends on temperature. Every time the heater raises the air temperature by 1 C, RH at that moisture content drops by roughly 3 to 4 points, so your humidity loop reacts to the heater even when no water has left the air.
Two changes that usually settle it:
1. Control a humidity measure that doesn’t move with temperature: absolute humidity (g/m3) or dew point. Compute it on the ESP32 from temp and RH (Magnus formula) and run the humidifier on that. At a fixed temp setpoint, 60 %RH at 25 C is about 13.8 g/m3, so that becomes your setpoint.
2. Separate the speeds. Keep the temperature loop fast and make the humidity loop at least 5 times slower (a minimum on time and off time for the humidifier, say 60 s each, and a deadband of about 0.5 g/m3). Then the temperature loop absorbs the mist’s cooling before the humidity loop decides anything.
For the board, Megan’s chart is the right one. In the line chart’s Series rows set rh and humid_on to Value axis Right, add a threshold line at your setpoints, and send abs_hum as a fifth key so you can watch the new loop. Chart settings are on Chart cards.

