blob: 06db58b3f1c2c8aa6530106498691d4490119990 [file]
/*
*
* Copyright (c) 2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app/ConcreteAttributePath.h>
#include <app/util/attribute-storage.h>
#include <protocols/interaction_model/Constants.h>
#include "Setpoint.h"
#include "SetpointAttributes.h"
#include "SetpointLimits.h"
#include "SetpointRange.h"
#include "Temperature.h"
namespace chip {
namespace app {
namespace Clusters {
namespace Thermostat {
class Setpoints
{
public:
enum class ClampMode : uint8_t
{
kDontClamp,
kClamp,
};
bool autoSupported = false;
bool heatSupported = false;
bool coolSupported = false;
bool occupancySupported = false;
bool eventsSupported = false;
AbsoluteSetpointLimits absoluteHeatLimits;
AbsoluteSetpointLimits absoluteCoolLimits;
UserSetpointLimits userHeatLimits;
UserSetpointLimits userCoolLimits;
SetpointRange occupiedRange;
SetpointRange unoccupiedRange;
temperature deadBand;
Setpoints() :
absoluteHeatLimits(AbsoluteSetpoint(Attributes::AbsMinHeatSetpointLimit::Id, kDefaultAbsMinHeatSetpointLimit),
AbsoluteSetpoint(Attributes::AbsMaxHeatSetpointLimit::Id, kDefaultAbsMaxHeatSetpointLimit)),
absoluteCoolLimits(AbsoluteSetpoint(Attributes::AbsMinCoolSetpointLimit::Id, kDefaultAbsMinCoolSetpointLimit),
AbsoluteSetpoint(Attributes::AbsMaxCoolSetpointLimit::Id, kDefaultAbsMaxCoolSetpointLimit)),
userHeatLimits(OptionalSetpoint(Attributes::MinHeatSetpointLimit::Id, absoluteHeatLimits.minimum),
OptionalSetpoint(Attributes::MaxHeatSetpointLimit::Id, absoluteHeatLimits.maximum)),
userCoolLimits(OptionalSetpoint(Attributes::MinCoolSetpointLimit::Id, absoluteCoolLimits.minimum),
OptionalSetpoint(Attributes::MaxCoolSetpointLimit::Id, absoluteCoolLimits.maximum)),
occupiedRange(AbsoluteSetpoint(Attributes::OccupiedHeatingSetpoint::Id, kDefaultHeatingSetpoint),
AbsoluteSetpoint(Attributes::OccupiedCoolingSetpoint::Id, kDefaultCoolingSetpoint)),
unoccupiedRange(AbsoluteSetpoint(Attributes::UnoccupiedHeatingSetpoint::Id, kDefaultHeatingSetpoint),
AbsoluteSetpoint(Attributes::UnoccupiedCoolingSetpoint::Id, kDefaultCoolingSetpoint)),
deadBand(kDefaultDeadBand)
{}
Setpoints(const Setpoints & spl) :
autoSupported(spl.autoSupported), heatSupported(spl.heatSupported), coolSupported(spl.coolSupported),
occupancySupported(spl.occupancySupported), eventsSupported(spl.eventsSupported),
absoluteHeatLimits(spl.absoluteHeatLimits), absoluteCoolLimits(spl.absoluteCoolLimits),
userHeatLimits(OptionalSetpoint(spl.userHeatLimits.minimum, absoluteHeatLimits.minimum),
OptionalSetpoint(spl.userHeatLimits.maximum, absoluteHeatLimits.maximum)),
userCoolLimits(OptionalSetpoint(spl.userCoolLimits.minimum, absoluteCoolLimits.minimum),
OptionalSetpoint(spl.userCoolLimits.maximum, absoluteCoolLimits.maximum)),
occupiedRange(spl.occupiedRange), unoccupiedRange(spl.unoccupiedRange), deadBand(spl.deadBand)
{}
Setpoints & operator=(const Setpoints & other)
{
if (this == &other)
{
return *this;
}
autoSupported = other.autoSupported;
heatSupported = other.heatSupported;
coolSupported = other.coolSupported;
occupancySupported = other.occupancySupported;
eventsSupported = other.eventsSupported;
absoluteHeatLimits = other.absoluteHeatLimits;
absoluteCoolLimits = other.absoluteCoolLimits;
userHeatLimits = UserSetpointLimits(OptionalSetpoint(other.userHeatLimits.minimum, absoluteHeatLimits.minimum),
OptionalSetpoint(other.userHeatLimits.maximum, absoluteHeatLimits.maximum));
userCoolLimits = UserSetpointLimits(OptionalSetpoint(other.userCoolLimits.minimum, absoluteCoolLimits.minimum),
OptionalSetpoint(other.userCoolLimits.maximum, absoluteCoolLimits.maximum));
occupiedRange = other.occupiedRange;
unoccupiedRange = other.unoccupiedRange;
deadBand = other.deadBand;
return *this;
}
/*
Checks to make sure that the setpoints follow the rules from the Matter spec
*/
bool Valid();
/*
Get the appropriate setpoint range, based on occupancy.
*/
SetpointRange & GetRange(chip::app::Clusters::Thermostat::OccupancyBitmap occupancy)
{
return occupancy == OccupancyBitmap::kOccupied ? occupiedRange : unoccupiedRange;
}
/*
Get the appropriate setpoint limits, based on mode
*/
SetpointLimits<AbsoluteSetpoint> GetLimits(chip::app::Clusters::Thermostat::SystemModeEnum mode);
/*
* Change the heating value of a given setpoint range.
*
* @param range The setpoint range to modify.
* @param heat The new heating setpoint value to set for the given range.
* @param clamp Whether to clamp the setpoint range.
* @param changedAttributes The set of attributes changed by this operation.
* @return The status of the operation.
*/
Protocols::InteractionModel::Status ChangeRangeHeating(SetpointRange & range, temperature heat, ClampMode clamp,
SetpointAttributes & changedAttributes);
/**
* Change the cooling value of a given setpoint range.
*
* @param range The setpoint range to modify.
* @param cool The new cooling setpoint value to set for the given range.
* @param clamp Whether to clamp the setpoint range.
* @param changedAttributes The set of attributes changed by this operation.
* @return The status of the operation.
*/
Protocols::InteractionModel::Status ChangeRangeCooling(SetpointRange & range, temperature cool, ClampMode clamp,
SetpointAttributes & changedAttributes);
/**
* Change either or both of the values of a given setpoint range.
*
* @param range The setpoint range to modify.
* @param heat The optional new heating setpoint value to set for the given range.
* @param cool The optional new cooling setpoint value to set for the given range.
* @param clamp Whether to clamp the setpoint range to the limits associated with it.
* @param changedAttributes The set of attributes changed by this operation.
* @return The status of the operation.
*/
Protocols::InteractionModel::Status ChangeRange(SetpointRange & range, Optional<temperature> heat, Optional<temperature> cool,
ClampMode clamp, SetpointAttributes & changedAttributes);
/**
* Change the minimum value of a given setpoint limit
*
* @param limits The setpoint limits to modify.
* @param min The new minimum setpoint value to set for the given limits.
* @param changedAttributes The set of attributes changed by this operation.
* @return The status of the operation.
*/
Protocols::InteractionModel::Status ChangeLimitMinimum(UserSetpointLimits & limits, AbsoluteSetpointLimits & absoluteLimits,
temperature min, SetpointAttributes & changedAttributes);
/**
* Change the maximum value of a given setpoint limit
*
* @param limits The setpoint limits to modify.
* @param max The new maximum setpoint value to set for the given limits.
* @param changedAttributes The set of attributes changed by this operation.
* @return The status of the operation.
*/
Protocols::InteractionModel::Status ChangeLimitMaximum(UserSetpointLimits & limits, AbsoluteSetpointLimits & absoluteLimits,
temperature max, SetpointAttributes & changedAttributes);
/**
* Attempt to fix any violations of the setpoint rules
* @param changedAttributes The set of attributes that were changed prior to this operation.
* @return The status of the operation; Success if the setpoints are now valid, ConstraintError if it was not possible to fix
* them
*/
Protocols::InteractionModel::Status Fix(SetpointAttributes & changedAttributes);
private:
/*
Change either the min or max value of a setpoint limits
@param limits The setpoint limits to modify.
@param min The new minimum setpoint value to set for the given limits.
@param max The new maximum setpoint value to set for the given limits.
@param changedAttributes The set of attributes changed by this operation.
@return The status of the operation; Success if the setpoints are now valid, ConstraintError if it was not possible to fix them
*/
Protocols::InteractionModel::Status ChangeLimits(UserSetpointLimits & limits, AbsoluteSetpointLimits & absoluteLimits,
Optional<temperature> min, Optional<temperature> max,
SetpointAttributes & changedAttributes);
/*
Attempt to fix the user setpoint limits to comply with the deadband
@param heatLimit The heating setpoint limit to modify.
@param coolLimit The cooling setpoint limit to modify.
@param absoluteHeatLimit The absolute heat setpoint limit.
@param absoluteCoolLimit The absolute cooling setpoint limit.
@param changedAttributes The set of attributes changed before this operation.
@param fixedAttributes The set of attributes fixed by this operation.
*/
void FixUserLimitDeadband(OptionalSetpoint & heatLimit, OptionalSetpoint & coolLimit, temperature absoluteHeatLimit,
temperature absoluteCoolLimit, SetpointAttributes & changedAttributes,
SetpointAttributes & fixedAttributes);
/*
Attempt to fix a given user setpoint limits to comply with the absolute limits and the deadband
@param absoluteLimits The absolute setpoint limits that apply to the user setpoint limits.
@param userLimits The user setpoint limits to modify.
@param changedAttributes The set of attributes changed before this operation.
@param fixedAttributes The set of attributes fixed by this operation.
*/
void FixUserLimits(AbsoluteSetpointLimits & absoluteLimits, UserSetpointLimits & userLimits,
SetpointAttributes & changedAttributes, SetpointAttributes & fixedAttributes);
/*
Attempt to fix a given setpoint range to comply with all setpoint rules
@param range The setpoint range to modify.
@param changedAttributes The set of attributes changed before this operation.
@param fixedAttributes The set of attributes fixed by this operation.
*/
void FixRange(SetpointRange & range, SetpointAttributes & changedAttributes, SetpointAttributes & fixedAttributes);
bool ViolatesDeadband(const Setpoint & max, const Setpoint & min) const
{
return (max.Temperature() - min.Temperature()) < static_cast<int32_t>(deadBand);
}
};
/*
Load setpoints from the Matter Data Storage
@param endpoint The endpoint to load setpoints from
@param setpoints The Setpoints object to load setpoints into
@return The status of the operation
*/
Protocols::InteractionModel::Status LoadSetpoints(EndpointId endpoint, Setpoints & setpoints);
/*
Save setpoints to the Matter Data Storage
@param endpoint The endpoint to save setpoints to
@param setpoints The Setpoints object to save setpoints from
@param changedAttributes The set of attributes changed by this operation
@return The status of the operation
*/
Protocols::InteractionModel::Status SaveSetpoints(EndpointId endpoint, Setpoints & setpoints,
SetpointAttributes & changedAttributes);
/*
Save first dirty setpoint to the Matter Data Storage.
This method is temporary until the conversion to code-driven cluster. See MatterThermostatClusterServerPreAttributeChangedCallback
for details.
@param endpoint The endpoint to save first dirty setpoint to
@param setpoints The Setpoints object to save first dirty setpoint from
@param changedAttributes The set of attributes changed by this operation
@return The status of the operation
*/
Protocols::InteractionModel::Status SaveFirstDirtySetpoint(EndpointId endpoint, Setpoints & setpoints,
SetpointAttributes & changedAttributes);
} // namespace Thermostat
} // namespace Clusters
} // namespace app
} // namespace chip