@@ -22,16 +22,17 @@ struct APB::Heater::Private {
2222 std::optional<float > temperature;
2323 float targetTemperature;
2424 float dewpointOffset;
25+ float rampOffset = 0 ;
2526
2627 Task loopTask;
2728 char log_scope[20 ];
2829 uint8_t index;
2930 Heater::GetTargetTemperature getTargetTemperature;
3031
31- void setup ();
32+ void privateSetup ();
3233 void loop ();
3334 void readTemperature ();
34- void setDuty (float pwm);
35+ void writePinDuty (float pwm);
3536 float getDuty () const ;
3637
3738#ifdef APB_HEATER_TEMPERATURE_SENSOR_THERMISTOR
@@ -69,7 +70,7 @@ void APB::Heater::setup(uint8_t index, Scheduler &scheduler) {
6970 d->index = index;
7071 sprintf (d->log_scope , " Heater[%d] -" , index);
7172
72- d->setup ();
73+ d->privateSetup ();
7374
7475 d->loopTask .set (APB_HEATER_UPDATE_INTERVAL_SECONDS * 1000 , TASK_FOREVER, std::bind (&Heater::Private::loop, d));
7576 scheduler.addTask (d->loopTask );
@@ -121,19 +122,20 @@ uint8_t APB::Heater::index() const {
121122}
122123
123124
124- bool APB::Heater::setTemperature (float targetTemperature, float maxDuty) {
125+ bool APB::Heater::setTemperature (float targetTemperature, float maxDuty, float rampOffset ) {
125126 if (!this ->temperature ().has_value ()) {
126127 Log.warningln (TEMPERATURE_NOT_FOUND_WARNING_LOG, d->log_scope );
127128 return false ;
128129 }
129130 d->targetTemperature = targetTemperature;
130131 d->pwm = maxDuty;
131132 d->mode = Heater::Mode::target_temperature;
133+ d->rampOffset = rampOffset >= 0 ? rampOffset : 0 ;
132134 d->loop ();
133135 return true ;
134136}
135137
136- bool APB::Heater::setDewpoint (float offset, float maxDuty) {
138+ bool APB::Heater::setDewpoint (float offset, float maxDuty, float rampOffset ) {
137139 if (!this ->temperature ().has_value ()) {
138140 Log.warningln (TEMPERATURE_NOT_FOUND_WARNING_LOG, d->log_scope );
139141 return false ;
@@ -143,12 +145,14 @@ bool APB::Heater::setDewpoint(float offset, float maxDuty) {
143145 return false ;
144146 }
145147 d->dewpointOffset = offset;
148+ d->rampOffset = rampOffset >= 0 ? rampOffset : 0 ;
146149 d->pwm = maxDuty;
147150 d->mode = Heater::Mode::dewpoint;
148151 d->loop ();
149152 return true ;
150153}
151154
155+
152156std::optional<float > APB::Heater::targetTemperature () const {
153157 if (d->mode != Heater::Mode::target_temperature) {
154158 return {};
@@ -163,6 +167,13 @@ std::optional<float> APB::Heater::dewpointOffset() const {
163167 return {d->dewpointOffset };
164168}
165169
170+ std::optional<float > APB::Heater::rampOffset () const {
171+ if (d->mode != Mode::dewpoint && d->mode != Mode::target_temperature) {
172+ return {};
173+ }
174+ return {d->rampOffset };
175+ }
176+
166177std::optional<float > APB::Heater::temperature () const {
167178 return d->temperature ;
168179}
@@ -187,11 +198,11 @@ void APB::Heater::Private::loop()
187198 }
188199
189200 if (mode == Heater::Mode::fixed) {
190- setDuty (pwm);
201+ writePinDuty (pwm);
191202 return ;
192203 }
193204 if (mode == Heater::Mode::off) {
194- setDuty (0 );
205+ writePinDuty (0 );
195206 return ;
196207 }
197208 // From nmow on we require a temperature sensor on the heater
@@ -201,40 +212,50 @@ void APB::Heater::Private::loop()
201212 return ;
202213 }
203214
204- float targetTemperature ;
215+ float dynamicTargetTemperature ;
205216 if (mode == Heater::Mode::target_temperature) {
206- targetTemperature = this ->targetTemperature ;
217+ dynamicTargetTemperature = this ->targetTemperature ;
207218 }
208219 if (mode == Heater::Mode::dewpoint) {
209220 if (!Ambient::Instance.reading ()) {
210221 Log.warningln (" %s Unable to set target temperature, ambient sensor not found." , log_scope);
211222 q->setDuty (0 );
212223 return ;
213224 }
214- targetTemperature = dewpointOffset + Ambient::Instance.reading ()->dewpoint ();
225+ dynamicTargetTemperature = dewpointOffset + Ambient::Instance.reading ()->dewpoint ();
215226 }
216227
217228 float currentTemperature = temperature.value ();
218- Log.traceln (" %s Got target temperature=`%F`" , log_scope, targetTemperature );
229+ Log.traceln (" %s Got target temperature=`%F`" , log_scope, dynamicTargetTemperature );
219230 Log.traceln (" %s current temperature=`%F`" , log_scope, currentTemperature);
220- if (currentTemperature < targetTemperature) {
221- Log.infoln (" %s - temperature `%F` lower than target temperature `%F`, setting PWM to `%F`" , log_scope, currentTemperature, targetTemperature, pwm);
222- setDuty (pwm);
231+ if (currentTemperature < dynamicTargetTemperature) {
232+ float rampFactor = rampOffset > 0 ? (dynamicTargetTemperature - currentTemperature)/rampOffset : 1 ;
233+ float targetPWM = std::max (0 .f , std::min (1 .f , rampFactor));
234+ Log.infoln (" %s - temperature `%F` lower than target temperature `%F`, ramp=`%F` and max PWM is `%F`, ramp factor=`%F`, setting PWM to `%F`" ,
235+ log_scope,
236+ currentTemperature,
237+ dynamicTargetTemperature,
238+ rampOffset,
239+ pwm,
240+ rampFactor,
241+ targetPWM
242+ );
243+ writePinDuty (targetPWM);
223244 } else {
224- Log.infoln (" %s - temperature `%F` reached target temperature `%F`, setting PWM to 0" , log_scope, currentTemperature, targetTemperature );
225- setDuty (0 );
245+ Log.infoln (" %s - temperature `%F` reached target temperature `%F`, setting PWM to 0" , log_scope, currentTemperature, dynamicTargetTemperature );
246+ writePinDuty (0 );
226247 }
227248}
228249
229250#ifdef APB_HEATER_TEMPERATURE_SENSOR_THERMISTOR
230251#define ANALOG_READ_RES 12
231252#define MAX_PWM 255.0
232- void APB::Heater::Private::setup () {
253+ void APB::Heater::Private::privateSetup () {
233254 static const float analogReadMax = std::pow (2 , ANALOG_READ_RES) - 1 ;
234255 pinout = &heaters_pinout[index];
235256 Log.traceln (" %s Configuring PWM thermistor heater: Thermistor pin=%d, PWM pin=%d, analogReadMax=%F" , log_scope, pinout->thermistor , pinout->pwm , analogReadMax);
236257 analogReadResolution (ANALOG_READ_RES);
237- setDuty (0 );
258+ writePinDuty (0 );
238259 if (pinout->thermistor != -1 ) {
239260 smoothThermistor = std::make_unique<SmoothThermistor>(
240261 pinout->thermistor ,
@@ -263,7 +284,7 @@ float APB::Heater::Private::getDuty() const {
263284 return this ->pwmValue /MAX_PWM;
264285}
265286
266- void APB::Heater::Private::setDuty (float pwm) {
287+ void APB::Heater::Private::writePinDuty (float pwm) {
267288 int16_t newPWMValue = MAX_PWM * pwm;
268289 if (newPWMValue != pwmValue) {
269290 pwmValue = newPWMValue;
0 commit comments