blob: c39a757a8b0644e1c7f0519919519da3cad899b2 [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 <thermostat-manager.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 = kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType;
mNextFreeIndexInPresetsList = 0;
mNextFreeIndexInPendingPresetsList = 0;
InitializePresetTypes();
InitializePresets();
memset(mActivePresetHandleData, 0, sizeof(mActivePresetHandleData));
mActivePresetHandleDataSize = 0;
}
void ThermostatDelegate::InitializePresetTypes()
{
PresetScenarioEnum presetScenarioEnumArray[kMaxNumberOfPresetTypes] = {
PresetScenarioEnum::kOccupied, PresetScenarioEnum::kUnoccupied, PresetScenarioEnum::kSleep,
PresetScenarioEnum::kWake, PresetScenarioEnum::kVacation, PresetScenarioEnum::kGoingToSleep
};
static_assert(ArraySize(presetScenarioEnumArray) <= ArraySize(mPresetTypes));
uint8_t index = 0;
for (PresetScenarioEnum presetScenario : presetScenarioEnumArray)
{
mPresetTypes[index].presetScenario = presetScenario;
mPresetTypes[index].numberOfPresets = kMaxNumberOfPresetsOfEachType;
mPresetTypes[index].presetTypeFeatures =
(presetScenario == PresetScenarioEnum::kOccupied || presetScenario == PresetScenarioEnum::kUnoccupied)
? PresetTypeFeaturesBitmap::kAutomatic
: PresetTypeFeaturesBitmap::kSupportsNames;
index++;
}
}
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)
{
if (index < ArraySize(mPresetTypes))
{
presetType = mPresetTypes[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(MutableByteSpan & activePresetHandle)
{
return CopySpanToMutableSpan(ByteSpan(mActivePresetHandleData, mActivePresetHandleDataSize), activePresetHandle);
}
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::GetAtomicWriteTimeout(DataModel::DecodableList<AttributeId> attributeRequests,
System::Clock::Milliseconds16 timeoutRequest)
{
auto attributeIdsIter = attributeRequests.begin();
bool requestedPresets = false, requestedSchedules = false;
while (attributeIdsIter.Next())
{
auto & attributeId = attributeIdsIter.GetValue();
switch (attributeId)
{
case Attributes::Presets::Id:
requestedPresets = true;
break;
case Attributes::Schedules::Id:
requestedSchedules = true;
break;
default:
return System::Clock::Milliseconds16(0);
}
}
if (attributeIdsIter.GetStatus() != CHIP_NO_ERROR)
{
return System::Clock::Milliseconds16(0);
}
auto timeout = System::Clock::Milliseconds16(0);
if (requestedPresets)
{
// If the client expects to edit the presets, then we'll give it 3 seconds to do so
timeout += std::chrono::milliseconds(3000);
}
if (requestedSchedules)
{
// If the client expects to edit the schedules, then we'll give it 9 seconds to do so
timeout += std::chrono::milliseconds(9000);
}
// If the client requested an even smaller timeout, then use that one
return std::min(timeoutRequest, timeout);
}
void ThermostatDelegate::InitializePendingPresets()
{
mNextFreeIndexInPendingPresetsList = 0;
for (uint8_t indexInPresets = 0; indexInPresets < mNextFreeIndexInPresetsList; indexInPresets++)
{
mPendingPresets[mNextFreeIndexInPendingPresetsList] = mPresets[indexInPresets];
mNextFreeIndexInPendingPresetsList++;
}
}
CHIP_ERROR ThermostatDelegate::AppendToPendingPresetList(const PresetStruct::Type & preset)
{
if (mNextFreeIndexInPendingPresetsList < ArraySize(mPendingPresets))
{
mPendingPresets[mNextFreeIndexInPendingPresetsList] = preset;
if (preset.presetHandle.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.presetScenario) };
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::ApplyPendingPresets()
{
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;
}