blob: da58c840049275b5635b4b38470931c7f3838306 [file] [log] [blame]
/*
*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* 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.
*/
#include <thermostat-delegate-impl.h>
#include <app-common/zap-generated/attributes/Accessors.h>
#include <lib/support/Span.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters::Thermostat;
using namespace chip::app::Clusters::Thermostat::Structs;
ThermostatDelegate ThermostatDelegate::sInstance;
ThermostatDelegate::ThermostatDelegate()
{
mNumberOfPresets = kMaxNumberOfPresetsSupported;
mNextFreeIndexInPresetsList = 0;
mNextFreeIndexInPendingPresetsList = 0;
InitializePresets();
memset(mActivePresetHandleData, 0, sizeof(mActivePresetHandleData));
mActivePresetHandleDataSize = 0;
}
void ThermostatDelegate::InitializePresets()
{
// Initialize the presets with 2 built in presets - occupied and unoccupied.
PresetScenarioEnum presetScenarioEnumArray[2] = { PresetScenarioEnum::kOccupied, PresetScenarioEnum::kUnoccupied };
static_assert(ArraySize(presetScenarioEnumArray) <= ArraySize(mPresets));
uint8_t index = 0;
for (PresetScenarioEnum presetScenario : presetScenarioEnumArray)
{
mPresets[index].SetPresetScenario(presetScenario);
// Set the preset handle to the preset scenario value as a unique id.
const uint8_t handle[] = { static_cast<uint8_t>(presetScenario) };
mPresets[index].SetPresetHandle(DataModel::MakeNullable(ByteSpan(handle)));
mPresets[index].SetName(NullOptional);
int16_t coolingSetpointValue = static_cast<int16_t>(2500 + (index * 100));
mPresets[index].SetCoolingSetpoint(MakeOptional(coolingSetpointValue));
int16_t heatingSetpointValue = static_cast<int16_t>(2100 - (index * 100));
mPresets[index].SetHeatingSetpoint(MakeOptional(heatingSetpointValue));
mPresets[index].SetBuiltIn(DataModel::MakeNullable(true));
index++;
}
// Set the value of the next free index in the presets list.
mNextFreeIndexInPresetsList = index;
}
CHIP_ERROR ThermostatDelegate::GetPresetTypeAtIndex(size_t index, PresetTypeStruct::Type & presetType)
{
static PresetTypeStruct::Type presetTypes[] = {
{ .presetScenario = PresetScenarioEnum::kOccupied,
.numberOfPresets = kMaxNumberOfPresetsOfEachType,
.presetTypeFeatures = to_underlying(PresetTypeFeaturesBitmap::kAutomatic) },
{ .presetScenario = PresetScenarioEnum::kUnoccupied,
.numberOfPresets = kMaxNumberOfPresetsOfEachType,
.presetTypeFeatures = to_underlying(PresetTypeFeaturesBitmap::kAutomatic) },
{ .presetScenario = PresetScenarioEnum::kSleep,
.numberOfPresets = kMaxNumberOfPresetsOfEachType,
.presetTypeFeatures = to_underlying(PresetTypeFeaturesBitmap::kSupportsNames) },
{ .presetScenario = PresetScenarioEnum::kWake,
.numberOfPresets = kMaxNumberOfPresetsOfEachType,
.presetTypeFeatures = to_underlying(PresetTypeFeaturesBitmap::kSupportsNames) },
{ .presetScenario = PresetScenarioEnum::kVacation,
.numberOfPresets = kMaxNumberOfPresetsOfEachType,
.presetTypeFeatures = to_underlying(PresetTypeFeaturesBitmap::kSupportsNames) },
{ .presetScenario = PresetScenarioEnum::kUserDefined,
.numberOfPresets = kMaxNumberOfPresetsOfEachType,
.presetTypeFeatures = to_underlying(PresetTypeFeaturesBitmap::kSupportsNames) },
};
if (index < ArraySize(presetTypes))
{
presetType = presetTypes[index];
return CHIP_NO_ERROR;
}
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
}
uint8_t ThermostatDelegate::GetNumberOfPresets()
{
return mNumberOfPresets;
}
CHIP_ERROR ThermostatDelegate::GetPresetAtIndex(size_t index, PresetStructWithOwnedMembers & preset)
{
if (index < mNextFreeIndexInPresetsList)
{
preset = mPresets[index];
return CHIP_NO_ERROR;
}
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
}
CHIP_ERROR ThermostatDelegate::GetActivePresetHandle(DataModel::Nullable<MutableByteSpan> & activePresetHandle)
{
if (mActivePresetHandleDataSize != 0)
{
ReturnErrorOnFailure(
CopySpanToMutableSpan(ByteSpan(mActivePresetHandleData, mActivePresetHandleDataSize), activePresetHandle.Value()));
activePresetHandle.Value().reduce_size(mActivePresetHandleDataSize);
}
else
{
activePresetHandle.SetNull();
}
return CHIP_NO_ERROR;
}
CHIP_ERROR ThermostatDelegate::SetActivePresetHandle(const DataModel::Nullable<ByteSpan> & newActivePresetHandle)
{
if (!newActivePresetHandle.IsNull())
{
size_t newActivePresetHandleSize = newActivePresetHandle.Value().size();
if (newActivePresetHandleSize > sizeof(mActivePresetHandleData))
{
ChipLogError(NotSpecified,
"Failed to set ActivePresetHandle. newActivePresetHandle size %u is larger than preset handle size %u",
static_cast<uint8_t>(newActivePresetHandleSize), static_cast<uint8_t>(kPresetHandleSize));
return CHIP_ERROR_NO_MEMORY;
}
memcpy(mActivePresetHandleData, newActivePresetHandle.Value().data(), newActivePresetHandleSize);
mActivePresetHandleDataSize = newActivePresetHandleSize;
ChipLogDetail(NotSpecified, "Set ActivePresetHandle to ");
ChipLogByteSpan(NotSpecified, newActivePresetHandle.Value());
}
else
{
memset(mActivePresetHandleData, 0, sizeof(mActivePresetHandleData));
mActivePresetHandleDataSize = 0;
ChipLogDetail(NotSpecified, "Clear ActivePresetHandle");
}
return CHIP_NO_ERROR;
}
std::optional<System::Clock::Milliseconds16> ThermostatDelegate::GetMaxAtomicWriteTimeout(chip::AttributeId attributeId)
{
switch (attributeId)
{
case Attributes::Presets::Id:
// If the client expects to edit the presets, then we'll give it 3 seconds to do so
return std::chrono::milliseconds(3000);
case Attributes::Schedules::Id:
// If the client expects to edit the schedules, then we'll give it 9 seconds to do so
return std::chrono::milliseconds(9000);
default:
return std::nullopt;
}
}
void ThermostatDelegate::InitializePendingPresets()
{
mNextFreeIndexInPendingPresetsList = 0;
for (uint8_t indexInPresets = 0; indexInPresets < mNextFreeIndexInPresetsList; indexInPresets++)
{
mPendingPresets[mNextFreeIndexInPendingPresetsList] = mPresets[indexInPresets];
mNextFreeIndexInPendingPresetsList++;
}
}
CHIP_ERROR ThermostatDelegate::AppendToPendingPresetList(const PresetStructWithOwnedMembers & preset)
{
if (mNextFreeIndexInPendingPresetsList < ArraySize(mPendingPresets))
{
mPendingPresets[mNextFreeIndexInPendingPresetsList] = preset;
if (preset.GetPresetHandle().IsNull())
{
// TODO: #34556 Since we support only one preset of each type, using the octet string containing the preset scenario
// suffices as the unique preset handle. Need to fix this to actually provide unique handles once multiple presets of
// each type are supported.
const uint8_t handle[] = { static_cast<uint8_t>(preset.GetPresetScenario()) };
mPendingPresets[mNextFreeIndexInPendingPresetsList].SetPresetHandle(DataModel::MakeNullable(ByteSpan(handle)));
}
mNextFreeIndexInPendingPresetsList++;
return CHIP_NO_ERROR;
}
return CHIP_ERROR_WRITE_FAILED;
}
CHIP_ERROR ThermostatDelegate::GetPendingPresetAtIndex(size_t index, PresetStructWithOwnedMembers & preset)
{
if (index < mNextFreeIndexInPendingPresetsList)
{
preset = mPendingPresets[index];
return CHIP_NO_ERROR;
}
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
}
CHIP_ERROR ThermostatDelegate::CommitPendingPresets()
{
mNextFreeIndexInPresetsList = 0;
for (uint8_t indexInPendingPresets = 0; indexInPendingPresets < mNextFreeIndexInPendingPresetsList; indexInPendingPresets++)
{
const PresetStructWithOwnedMembers & pendingPreset = mPendingPresets[indexInPendingPresets];
mPresets[mNextFreeIndexInPresetsList] = pendingPreset;
mNextFreeIndexInPresetsList++;
}
return CHIP_NO_ERROR;
}
void ThermostatDelegate::ClearPendingPresetList()
{
mNextFreeIndexInPendingPresetsList = 0;
}