21
21
#include < WhmManufacturer.h>
22
22
#include < water-heater-mode.h>
23
23
24
+ #include < algorithm>
25
+
24
26
using namespace chip ;
25
27
using namespace chip ::app;
26
28
using namespace chip ::app::Clusters;
@@ -29,10 +31,11 @@ using namespace chip::app::Clusters::WaterHeaterManagement;
29
31
using Protocols::InteractionModel::Status;
30
32
31
33
WaterHeaterManagementDelegate::WaterHeaterManagementDelegate (EndpointId clustersEndpoint) :
32
- mpWhmInstance(nullptr ), mpWhmManufacturer(nullptr ), mWaterTemperature(0 ), mReplacedWaterTemperature(0 ),
33
- mBoostTargetTemperatureReached(false ), mTankVolume(0 ), mEstimatedHeatRequired(0 ), mTankPercentage(0 ),
34
- mBoostState(BoostStateEnum::kInactive )
35
- {}
34
+ mpWhmInstance(nullptr ), mpWhmManufacturer(nullptr ), mTargetWaterTemperature(0 ), mWaterTemperature(0 ),
35
+ mColdWaterTemperature(0 ), mBoostTargetTemperatureReached(false ), mTankVolume(0 ),
36
+ mEstimatedHeatRequired(0 ), mTankPercentage(0 ), mBoostState(BoostStateEnum::kInactive )
37
+ {
38
+ }
36
39
37
40
void WaterHeaterManagementDelegate::SetWaterHeaterManagementInstance (WaterHeaterManagement::Instance & instance)
38
41
{
@@ -128,8 +131,6 @@ void WaterHeaterManagementDelegate::SetTankPercentage(Percent tankPercentage)
128
131
{
129
132
mTankPercentage = tankPercentage;
130
133
131
- CheckIfHeatNeedsToBeTurnedOnOrOff ();
132
-
133
134
MatterReportingAttributeChangeCallback (mEndpointId , WaterHeaterManagement::Id, Attributes::TankPercentage::Id);
134
135
}
135
136
}
@@ -201,13 +202,22 @@ Status WaterHeaterManagementDelegate::HandleBoost(uint32_t durationS, Optional<b
201
202
ChipLogError (AppServer, " HandleBoost: mpWhmManufacturer == nullptr" );
202
203
}
203
204
204
- if (status == Status::Success)
205
+ VerifyOrReturnValue (status == Status::Success, status);
206
+
207
+ // See if the heat needs to be turned on or off as a result of this boost command
208
+ status = ChangeHeatingIfNecessary ();
209
+ VerifyOrReturnValue (status == Status::Success, status);
210
+
211
+ // Now generate a BoostStarted event
212
+ err = GenerateBoostStartedEvent (durationS, oneShot, emergencyBoost, temporarySetpoint, targetPercentage, targetReheat);
213
+ if (err != CHIP_NO_ERROR)
205
214
{
206
- // See if the heat needs to be turned on or off as a result of this boost command
207
- status = CheckIfHeatNeedsToBeTurnedOnOrOff ();
215
+ ChipLogError (AppServer, " HandleBoost: Failed to send BoostStarted event: %" CHIP_ERROR_FORMAT, err.Format ());
216
+
217
+ return Status::Failure;
208
218
}
209
219
210
- return status ;
220
+ return Status::Success ;
211
221
}
212
222
213
223
void WaterHeaterManagementDelegate::BoostTimerExpiry (System::Layer * systemLayer, void * delegate)
@@ -236,7 +246,15 @@ void WaterHeaterManagementDelegate::HandleBoostTimerExpiry()
236
246
ChipLogError (AppServer, " HandleBoostTimerExpiry: mpWhmManufacturer == nullptr" );
237
247
}
238
248
239
- CheckIfHeatNeedsToBeTurnedOnOrOff ();
249
+ // Note ChangeHeatingIfNecessary can generate a BoostEnded event but only if the boost state is kActive
250
+ // which it cannot be when called from here.
251
+ ChangeHeatingIfNecessary ();
252
+
253
+ CHIP_ERROR err = GenerateBoostEndedEvent ();
254
+ if (err != CHIP_NO_ERROR)
255
+ {
256
+ ChipLogError (AppServer, " HandleBoostTimerExpiry: Failed to send BoostEnded event: %" CHIP_ERROR_FORMAT, err.Format ());
257
+ }
240
258
}
241
259
242
260
/* *
@@ -260,8 +278,18 @@ Status WaterHeaterManagementDelegate::HandleCancelBoost()
260
278
Status status = mpWhmManufacturer->BoostCommandCancelled ();
261
279
VerifyOrReturnValue (status == Status::Success, status);
262
280
263
- status = CheckIfHeatNeedsToBeTurnedOnOrOff ();
281
+ // Note ChangeHeatingIfNecessary can generate a BoostEnded event but only if the boost state is kActive
282
+ // which it cannot be when called from here.
283
+ status = ChangeHeatingIfNecessary ();
264
284
VerifyOrReturnValue (status == Status::Success, status);
285
+
286
+ CHIP_ERROR err = GenerateBoostEndedEvent ();
287
+ if (err != CHIP_NO_ERROR)
288
+ {
289
+ ChipLogError (AppServer, " HandleCancelBoost: Failed to send BoostEnded event: %" CHIP_ERROR_FORMAT, err.Format ());
290
+
291
+ return Status::Failure;
292
+ }
265
293
}
266
294
267
295
return Status::Success;
@@ -273,59 +301,75 @@ Status WaterHeaterManagementDelegate::HandleCancelBoost()
273
301
*
274
302
*********************************************************************************/
275
303
304
+ uint16_t WaterHeaterManagementDelegate::GetActiveTargetWaterTemperature () const
305
+ {
306
+ // Determine the target temperature. If a boost command is in progress and has a mBoostTemporarySetpoint value use that as the
307
+ // target temperature.
308
+ // Note, in practise the actual heating is likely to be controlled by the thermostat's occupiedHeatingSetpoint most of the
309
+ // time, and the TemporarySetpoint (if not null) would be overiding the thermostat's occupiedHeatingSetpoint.
310
+ // However, this code doesn't rely upon the thermostat cluster.
311
+ uint16_t targetTemperature = (mBoostState == BoostStateEnum::kActive && mBoostTemporarySetpoint .HasValue ())
312
+ ? static_cast <uint16_t >(mBoostTemporarySetpoint .Value ())
313
+ : mTargetWaterTemperature ;
314
+
315
+ return targetTemperature;
316
+ }
317
+
318
+ uint8_t WaterHeaterManagementDelegate::CalculateTankPercentage () const
319
+ {
320
+ int16_t tankPercentage = 100 * (mWaterTemperature - mColdWaterTemperature ) / (GetActiveTargetWaterTemperature () - mColdWaterTemperature );
321
+
322
+ tankPercentage = std::min (tankPercentage, static_cast <int16_t >(100 ));
323
+ tankPercentage = std::max (tankPercentage, static_cast <int16_t >(0 ));
324
+
325
+ return static_cast <uint8_t >(tankPercentage);
326
+ }
327
+
328
+ void WaterHeaterManagementDelegate::SetColdWaterTemperature (uint16_t coldWaterTemperature)
329
+ {
330
+ mColdWaterTemperature = coldWaterTemperature;
331
+ }
332
+
276
333
void WaterHeaterManagementDelegate::SetWaterTemperature (uint16_t waterTemperature)
277
334
{
278
335
mWaterTemperature = waterTemperature;
279
336
280
337
if (mpWhmInstance != nullptr && mpWhmInstance->HasFeature (Feature::kTankPercent ))
281
338
{
282
- mTankPercentage = 100 ;
339
+ // Recalculate the tankPercentage as the waterTemperature has changed
340
+ SetTankPercentage (CalculateTankPercentage ());
283
341
}
284
342
285
343
// See if the heat needs to be turned on or off
286
- CheckIfHeatNeedsToBeTurnedOnOrOff ();
344
+ ChangeHeatingIfNecessary ();
287
345
}
288
346
289
347
void WaterHeaterManagementDelegate::SetTargetWaterTemperature (uint16_t targetWaterTemperature)
290
348
{
291
349
mTargetWaterTemperature = targetWaterTemperature;
292
350
293
351
// See if the heat needs to be turned on or off
294
- CheckIfHeatNeedsToBeTurnedOnOrOff ();
352
+ ChangeHeatingIfNecessary ();
295
353
}
296
354
297
355
void WaterHeaterManagementDelegate::DrawOffHotWater (Percent percentageReplaced, uint16_t replacedWaterTemperature)
298
356
{
299
- // Only supported in the kTankPercent is supported.
357
+ // First calculate the new average water temperature
358
+ mWaterTemperature = (mWaterTemperature * (100 - percentageReplaced) + replacedWaterTemperature * percentageReplaced) / 100 ;
359
+
300
360
// Replaces percentageReplaced% of the water in the tank with water of a temperature replacedWaterTemperature
361
+ // Only supported if the kTankPercent feature is supported.
301
362
if (mpWhmInstance != nullptr && mpWhmInstance->HasFeature (Feature::kTankPercent ))
302
363
{
303
- // See if all of the water has now been replaced with replacedWaterTemperature
304
- if (mTankPercentage >= percentageReplaced)
305
- {
306
- mTankPercentage = static_cast <Percent>(mTankPercentage - percentageReplaced);
307
- }
308
- else
309
- {
310
- mTankPercentage = 0 ;
311
- }
312
-
313
- mReplacedWaterTemperature = replacedWaterTemperature;
364
+ SetTankPercentage (CalculateTankPercentage ());
314
365
315
- CheckIfHeatNeedsToBeTurnedOnOrOff ();
366
+ ChangeHeatingIfNecessary ();
316
367
}
317
368
}
318
369
319
370
bool WaterHeaterManagementDelegate::HasWaterTemperatureReachedTarget () const
320
371
{
321
- // Determine the target temperature. If a boost command is in progress and has a mBoostTemporarySetpoint value use that as the
322
- // target temperature.
323
- // Note, in practise the actual heating is likely to be controlled by the thermostat's occupiedHeatingSetpoint most of the
324
- // time, and the TemporarySetpoint (if not null) would be overiding the thermostat's occupiedHeatingSetpoint.
325
- // However, this code doesn't rely upon the thermostat cluster.
326
- uint16_t targetTemperature = (mBoostState == BoostStateEnum::kActive && mBoostTemporarySetpoint .HasValue ())
327
- ? static_cast <uint16_t >(mBoostTemporarySetpoint .Value ())
328
- : mTargetWaterTemperature ;
372
+ uint16_t targetTemperature = GetActiveTargetWaterTemperature ();
329
373
330
374
VerifyOrReturnValue (mWaterTemperature >= targetTemperature, false );
331
375
@@ -357,7 +401,7 @@ bool WaterHeaterManagementDelegate::HasWaterTemperatureReachedTarget() const
357
401
return true ;
358
402
}
359
403
360
- Status WaterHeaterManagementDelegate::CheckIfHeatNeedsToBeTurnedOnOrOff ()
404
+ Status WaterHeaterManagementDelegate::ChangeHeatingIfNecessary ()
361
405
{
362
406
VerifyOrReturnError (mpWhmManufacturer != nullptr , Status::InvalidInState);
363
407
@@ -384,6 +428,12 @@ Status WaterHeaterManagementDelegate::CheckIfHeatNeedsToBeTurnedOnOrOff()
384
428
mBoostEmergencyBoost .ClearValue ();
385
429
386
430
status = mpWhmManufacturer->BoostCommandCancelled ();
431
+
432
+ CHIP_ERROR err = GenerateBoostEndedEvent ();
433
+ if (err != CHIP_NO_ERROR)
434
+ {
435
+ ChipLogError (AppServer, " ChangeHeatingIfNecessary: Failed to send BoostEnded event: %" CHIP_ERROR_FORMAT, err.Format ());
436
+ }
387
437
}
388
438
389
439
// Turn the heating off
@@ -457,5 +507,6 @@ Status WaterHeaterManagementDelegate::SetWaterHeaterMode(uint8_t modeValue)
457
507
return status;
458
508
}
459
509
460
- return CheckIfHeatNeedsToBeTurnedOnOrOff ();
510
+ return ChangeHeatingIfNecessary ();
461
511
}
512
+
0 commit comments