From c91a779c5e937b1aabcd55a072f9268452f85a63 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Thu, 25 Jul 2024 10:32:04 -0400 Subject: [PATCH 01/17] Implement TC-SWTCH-2.4 and all-clusters button simulator (#34406) * Implement TC-SWTCH-2.4 and all-clusters button simulator - Implement TC-SWTCH-2.4 - Implement action switch button simulator to drive the test Testing done: - New test (TC-SWTCH-2.4) works using the button simulator * Restyled by clang-format * Restyled by autopep8 * Restyled by isort * Enable TC_SWTCH.py in CI * Fix lint * Fix typo that arose on file saving * Handle EOF in reading user input in matter testing support * Do not provide a stdin on python test runner and handle EOF on matter_testing_support * Fix up PICS execution for CI --------- Co-authored-by: Restyled.io Co-authored-by: Andrei Litvin --- .github/workflows/tests.yaml | 1 + .../linux/AllClustersCommandDelegate.cpp | 151 +++++++++ examples/all-clusters-app/linux/BUILD.gn | 3 + .../linux/ButtonEventsSimulator.cpp | 210 +++++++++++++ .../linux/ButtonEventsSimulator.h | 143 +++++++++ scripts/tests/run_python_test.py | 6 +- src/python_testing/TC_SWTCH.py | 290 ++++++++++++++++++ src/python_testing/matter_testing_support.py | 74 ++++- 8 files changed, 865 insertions(+), 13 deletions(-) create mode 100644 examples/all-clusters-app/linux/ButtonEventsSimulator.cpp create mode 100644 examples/all-clusters-app/linux/ButtonEventsSimulator.h create mode 100644 src/python_testing/TC_SWTCH.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d559612d2be60d..182a3bb3a9fadd 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -577,6 +577,7 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_3.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_4.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SC_7_1.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SWTCH.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestConformanceSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestMatterTestingSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestSpecParsingSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' diff --git a/examples/all-clusters-app/linux/AllClustersCommandDelegate.cpp b/examples/all-clusters-app/linux/AllClustersCommandDelegate.cpp index 8effe6426cc49d..3c42eb1dd6a32e 100644 --- a/examples/all-clusters-app/linux/AllClustersCommandDelegate.cpp +++ b/examples/all-clusters-app/linux/AllClustersCommandDelegate.cpp @@ -28,6 +28,7 @@ #include #include +#include "ButtonEventsSimulator.h" #include #include #include @@ -36,13 +37,155 @@ #include #include +#include #include +#include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::DeviceLayer; +namespace { + +std::unique_ptr sButtonSimulatorInstance{ nullptr }; + +bool HasNumericField(Json::Value & jsonValue, const std::string & field) +{ + return jsonValue.isMember(field) && jsonValue[field].isNumeric(); +} + +/** + * Named pipe handler for simulated long press on an action switch. + * + * Usage example: + * echo '{"Name": "SimulateActionSwitchLongPress", "EndpointId": 3, "ButtonId": 1, "LongPressDelayMillis": 800, + * "LongPressDurationMillis": 1000}' > /tmp/chip_all_clusters_fifo_1146610 + * + * JSON Arguments: + * - "Name": Must be "SimulateActionSwitchLongPress" + * - "EndpointId": number of endpoint having a switch cluster + * - "ButtonId": switch position in the switch cluster for "down" button (not idle) + * - "LongPressDelayMillis": Time in milliseconds before the LongPress + * - "LongPressDurationMillis": Total duration in milliseconds from start of the press to LongRelease + * + * @param jsonValue - JSON payload from named pipe + */ +void HandleSimulateActionSwitchLongPress(Json::Value & jsonValue) +{ + if (sButtonSimulatorInstance != nullptr) + { + ChipLogError(NotSpecified, "Button simulation already in progress! Ignoring request."); + return; + } + + bool hasEndpointId = HasNumericField(jsonValue, "EndpointId"); + bool hasButtonId = HasNumericField(jsonValue, "ButtonId"); + bool hasLongPressDelayMillis = HasNumericField(jsonValue, "LongPressDelayMillis"); + bool hasLongPressDurationMillis = HasNumericField(jsonValue, "LongPressDurationMillis"); + if (!hasEndpointId || !hasButtonId || !hasLongPressDelayMillis || !hasLongPressDurationMillis) + { + std::string inputJson = jsonValue.toStyledString(); + ChipLogError( + NotSpecified, + "Missing or invalid value for one of EndpointId, ButtonId, LongPressDelayMillis or LongPressDurationMillis in %s", + inputJson.c_str()); + return; + } + + EndpointId endpointId = static_cast(jsonValue["EndpointId"].asUInt()); + uint8_t buttonId = static_cast(jsonValue["ButtonId"].asUInt()); + System::Clock::Milliseconds32 longPressDelayMillis{ static_cast(jsonValue["LongPressDelayMillis"].asUInt()) }; + System::Clock::Milliseconds32 longPressDurationMillis{ static_cast(jsonValue["LongPressDurationMillis"].asUInt()) }; + auto buttonSimulator = std::make_unique(); + + bool success = buttonSimulator->SetMode(ButtonEventsSimulator::Mode::kModeLongPress) + .SetLongPressDelayMillis(longPressDelayMillis) + .SetLongPressDurationMillis(longPressDurationMillis) + .SetIdleButtonId(0) + .SetPressedButtonId(buttonId) + .SetEndpointId(endpointId) + .Execute([]() { sButtonSimulatorInstance.reset(); }); + + if (!success) + { + ChipLogError(NotSpecified, "Failed to start execution of button simulator!"); + return; + } + + sButtonSimulatorInstance = std::move(buttonSimulator); +} + +/** + * Named pipe handler for simulated multi-press on an action switch. + * + * Usage example: + * echo '{"Name": "SimulateActionSwitchMultiPress", "EndpointId": 3, "ButtonId": 1, "MultiPressPressedTimeMillis": 100, + * "MultiPressReleasedTimeMillis": 350, "MultiPressNumPresses": 2}' > /tmp/chip_all_clusters_fifo_1146610 + * + * JSON Arguments: + * - "Name": Must be "SimulateActionSwitchMultiPress" + * - "EndpointId": number of endpoint having a switch cluster + * - "ButtonId": switch position in the switch cluster for "down" button (not idle) + * - "MultiPressPressedTimeMillis": Pressed time in milliseconds for each press + * - "MultiPressReleasedTimeMillis": Released time in milliseconds after each press + * - "MultiPressNumPresses": Number of presses to simulate + * + * @param jsonValue - JSON payload from named pipe + */ +void HandleSimulateActionSwitchMultiPress(Json::Value & jsonValue) +{ + if (sButtonSimulatorInstance != nullptr) + { + ChipLogError(NotSpecified, "Button simulation already in progress! Ignoring request."); + return; + } + + bool hasEndpointId = HasNumericField(jsonValue, "EndpointId"); + bool hasButtonId = HasNumericField(jsonValue, "ButtonId"); + bool hasMultiPressPressedTimeMillis = HasNumericField(jsonValue, "MultiPressPressedTimeMillis"); + bool hasMultiPressReleasedTimeMillis = HasNumericField(jsonValue, "MultiPressReleasedTimeMillis"); + bool hasMultiPressNumPresses = HasNumericField(jsonValue, "MultiPressNumPresses"); + if (!hasEndpointId || !hasButtonId || !hasMultiPressPressedTimeMillis || !hasMultiPressReleasedTimeMillis || + !hasMultiPressNumPresses) + { + std::string inputJson = jsonValue.toStyledString(); + ChipLogError(NotSpecified, + "Missing or invalid value for one of EndpointId, ButtonId, MultiPressPressedTimeMillis, " + "MultiPressReleasedTimeMillis or MultiPressNumPresses in %s", + inputJson.c_str()); + return; + } + + EndpointId endpointId = static_cast(jsonValue["EndpointId"].asUInt()); + uint8_t buttonId = static_cast(jsonValue["ButtonId"].asUInt()); + System::Clock::Milliseconds32 multiPressPressedTimeMillis{ static_cast( + jsonValue["MultiPressPressedTimeMillis"].asUInt()) }; + System::Clock::Milliseconds32 multiPressReleasedTimeMillis{ static_cast( + jsonValue["MultiPressReleasedTimeMillis"].asUInt()) }; + uint8_t multiPressNumPresses = static_cast(jsonValue["MultiPressNumPresses"].asUInt()); + auto buttonSimulator = std::make_unique(); + + bool success = buttonSimulator->SetMode(ButtonEventsSimulator::Mode::kModeMultiPress) + .SetMultiPressPressedTimeMillis(multiPressPressedTimeMillis) + .SetMultiPressReleasedTimeMillis(multiPressReleasedTimeMillis) + .SetMultiPressNumPresses(multiPressNumPresses) + .SetIdleButtonId(0) + .SetPressedButtonId(buttonId) + .SetEndpointId(endpointId) + .Execute([]() { sButtonSimulatorInstance.reset(); }); + + if (!success) + { + ChipLogError(NotSpecified, "Failed to start execution of button simulator!"); + return; + } + + sButtonSimulatorInstance = std::move(buttonSimulator); +} + +} // namespace + AllClustersAppCommandHandler * AllClustersAppCommandHandler::FromJSON(const char * json) { Json::Reader reader; @@ -190,6 +333,14 @@ void AllClustersAppCommandHandler::HandleCommand(intptr_t context) std::string operation = self->mJsonValue["Operation"].asString(); self->OnOperationalStateChange(device, operation, self->mJsonValue["Param"]); } + else if (name == "SimulateActionSwitchLongPress") + { + HandleSimulateActionSwitchLongPress(self->mJsonValue); + } + else if (name == "SimulateActionSwitchMultiPress") + { + HandleSimulateActionSwitchMultiPress(self->mJsonValue); + } else { ChipLogError(NotSpecified, "Unhandled command: Should never happens"); diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index 3d52ef748de90d..a2f4ff0ab1f781 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -66,7 +66,10 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/energy-management-app/energy-management-common/src/device-energy-management-mode.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/energy-evse-mode.cpp", "AllClustersCommandDelegate.cpp", + "AllClustersCommandDelegate.h", "AppOptions.cpp", + "ButtonEventsSimulator.cpp", + "ButtonEventsSimulator.h", "ValveControlDelegate.cpp", "WindowCoveringManager.cpp", "include/tv-callbacks.cpp", diff --git a/examples/all-clusters-app/linux/ButtonEventsSimulator.cpp b/examples/all-clusters-app/linux/ButtonEventsSimulator.cpp new file mode 100644 index 00000000000000..44bf5657f5c2f6 --- /dev/null +++ b/examples/all-clusters-app/linux/ButtonEventsSimulator.cpp @@ -0,0 +1,210 @@ +/* + * + * 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 "ButtonEventsSimulator.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { + +namespace { + +void SetButtonPosition(EndpointId endpointId, uint8_t position) +{ + Clusters::Switch::Attributes::CurrentPosition::Set(endpointId, position); +} + +void EmitInitialPress(EndpointId endpointId, uint8_t newPosition) +{ + Clusters::Switch::Events::InitialPress::Type event{ newPosition }; + EventNumber eventNumber = 0; + + CHIP_ERROR err = LogEvent(event, endpointId, eventNumber); + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to log InitialPress event: %" CHIP_ERROR_FORMAT, err.Format()); + } + else + { + ChipLogProgress(NotSpecified, "Logged InitialPress(%u) on Endpoint %u", static_cast(newPosition), + static_cast(endpointId)); + } +} + +void EmitLongPress(EndpointId endpointId, uint8_t newPosition) +{ + Clusters::Switch::Events::LongPress::Type event{ newPosition }; + EventNumber eventNumber = 0; + + CHIP_ERROR err = LogEvent(event, endpointId, eventNumber); + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to log LongPress event: %" CHIP_ERROR_FORMAT, err.Format()); + } + else + { + ChipLogProgress(NotSpecified, "Logged LongPress(%u) on Endpoint %u", static_cast(newPosition), + static_cast(endpointId)); + } +} + +void EmitLongRelease(EndpointId endpointId, uint8_t previousPosition) +{ + Clusters::Switch::Events::LongRelease::Type event{}; + event.previousPosition = previousPosition; + EventNumber eventNumber = 0; + + CHIP_ERROR err = LogEvent(event, endpointId, eventNumber); + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to log LongRelease event: %" CHIP_ERROR_FORMAT, err.Format()); + } + else + { + ChipLogProgress(NotSpecified, "Logged LongRelease on Endpoint %u", static_cast(endpointId)); + } +} + +void EmitMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uint8_t count) +{ + Clusters::Switch::Events::MultiPressComplete::Type event{}; + event.previousPosition = previousPosition; + event.totalNumberOfPressesCounted = count; + EventNumber eventNumber = 0; + + CHIP_ERROR err = LogEvent(event, endpointId, eventNumber); + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to log MultiPressComplete event: %" CHIP_ERROR_FORMAT, err.Format()); + } + else + { + ChipLogProgress(NotSpecified, "Logged MultiPressComplete(count=%u) on Endpoint %u", static_cast(count), + static_cast(endpointId)); + } +} + +} // namespace + +void ButtonEventsSimulator::OnTimerDone(System::Layer * layer, void * appState) +{ + ButtonEventsSimulator * that = reinterpret_cast(appState); + that->Next(); +} + +bool ButtonEventsSimulator::Execute(DoneCallback && doneCallback) +{ + VerifyOrReturnValue(mIdleButtonId != mPressedButtonId, false); + + switch (mMode) + { + case Mode::kModeLongPress: + VerifyOrReturnValue(mLongPressDurationMillis > mLongPressDelayMillis, false); + SetState(State::kEmitStartOfLongPress); + break; + case Mode::kModeMultiPress: + VerifyOrReturnValue(mMultiPressPressedTimeMillis.count() > 0, false); + VerifyOrReturnValue(mMultiPressReleasedTimeMillis.count() > 0, false); + VerifyOrReturnValue(mMultiPressNumPresses > 0, false); + SetState(State::kEmitStartOfMultiPress); + break; + default: + return false; + } + mDoneCallback = std::move(doneCallback); + Next(); + return true; +} + +void ButtonEventsSimulator::SetState(ButtonEventsSimulator::State newState) +{ + ButtonEventsSimulator::State oldState = mState; + if (oldState != newState) + { + ChipLogProgress(NotSpecified, "ButtonEventsSimulator state change %u -> %u", static_cast(oldState), + static_cast(newState)); + } + + mState = newState; +} + +void ButtonEventsSimulator::StartTimer(System::Clock::Timeout duration) +{ + chip::DeviceLayer::SystemLayer().StartTimer(duration, &ButtonEventsSimulator::OnTimerDone, this); +} + +void ButtonEventsSimulator::Next() +{ + switch (mState) + { + case ButtonEventsSimulator::State::kIdle: { + ChipLogError(NotSpecified, "Found idle state where not expected!"); + break; + } + case ButtonEventsSimulator::State::kEmitStartOfLongPress: { + SetButtonPosition(mEndpointId, mPressedButtonId); + EmitInitialPress(mEndpointId, mPressedButtonId); + SetState(ButtonEventsSimulator::State::kEmitLongPress); + StartTimer(mLongPressDelayMillis); + break; + } + case ButtonEventsSimulator::State::kEmitLongPress: { + EmitLongPress(mEndpointId, mPressedButtonId); + SetState(ButtonEventsSimulator::State::kEmitLongRelease); + StartTimer(mLongPressDurationMillis - mLongPressDelayMillis); + break; + } + case ButtonEventsSimulator::State::kEmitLongRelease: { + SetButtonPosition(mEndpointId, mIdleButtonId); + EmitLongRelease(mEndpointId, mPressedButtonId); + SetState(ButtonEventsSimulator::State::kIdle); + mDoneCallback(); + break; + } + case ButtonEventsSimulator::State::kEmitStartOfMultiPress: { + EmitInitialPress(mEndpointId, mPressedButtonId); + StartTimer(mMultiPressNumPresses * (mMultiPressPressedTimeMillis + mMultiPressReleasedTimeMillis)); + SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress); + break; + } + case ButtonEventsSimulator::State::kEmitEndOfMultiPress: { + EmitMultiPressComplete(mEndpointId, mPressedButtonId, mMultiPressNumPresses); + SetState(ButtonEventsSimulator::State::kIdle); + mDoneCallback(); + break; + } + } +} + +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/linux/ButtonEventsSimulator.h b/examples/all-clusters-app/linux/ButtonEventsSimulator.h new file mode 100644 index 00000000000000..658da98f14fefd --- /dev/null +++ b/examples/all-clusters-app/linux/ButtonEventsSimulator.h @@ -0,0 +1,143 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace chip { +namespace app { + +/** + * State machine to emit button sequences. Configure with `SetXxx()` methods + * and then call `Execute()` with a functor to be called when done. + * + * The implementation has dependencies on SystemLayer (to start timers) and on + * EventLogging. + * + */ +class ButtonEventsSimulator +{ +public: + enum class Mode + { + kModeLongPress, + kModeMultiPress + }; + + using DoneCallback = std::function; + + ButtonEventsSimulator() = default; + + // Returns true on success to start execution, false on something going awry. + // `doneCallback` is called only if execution got started. + bool Execute(DoneCallback && doneCallback); + + ButtonEventsSimulator & SetLongPressDelayMillis(System::Clock::Milliseconds32 longPressDelayMillis) + { + mLongPressDelayMillis = longPressDelayMillis; + return *this; + } + + ButtonEventsSimulator & SetLongPressDurationMillis(System::Clock::Milliseconds32 longPressDurationMillis) + { + mLongPressDurationMillis = longPressDurationMillis; + return *this; + } + + ButtonEventsSimulator & SetMultiPressPressedTimeMillis(System::Clock::Milliseconds32 multiPressPressedTimeMillis) + { + mMultiPressPressedTimeMillis = multiPressPressedTimeMillis; + return *this; + } + + ButtonEventsSimulator & SetMultiPressReleasedTimeMillis(System::Clock::Milliseconds32 multiPressReleasedTimeMillis) + { + mMultiPressReleasedTimeMillis = multiPressReleasedTimeMillis; + return *this; + } + + ButtonEventsSimulator & SetMultiPressNumPresses(uint8_t multiPressNumPresses) + { + mMultiPressNumPresses = multiPressNumPresses; + return *this; + } + + ButtonEventsSimulator & SetIdleButtonId(uint8_t idleButtonId) + { + mIdleButtonId = idleButtonId; + return *this; + } + + ButtonEventsSimulator & SetPressedButtonId(uint8_t pressedButtonId) + { + mPressedButtonId = pressedButtonId; + return *this; + } + + ButtonEventsSimulator & SetMode(Mode mode) + { + mMode = mode; + return *this; + } + + ButtonEventsSimulator & SetEndpointId(EndpointId endpointId) + { + mEndpointId = endpointId; + return *this; + } + +private: + enum class State + { + kIdle = 0, + + kEmitStartOfLongPress = 1, + kEmitLongPress = 2, + kEmitLongRelease = 3, + + kEmitStartOfMultiPress = 4, + kEmitEndOfMultiPress = 5, + }; + + static void OnTimerDone(System::Layer * layer, void * appState); + void SetState(State newState); + void Next(); + void StartTimer(System::Clock::Timeout duration); + + DoneCallback mDoneCallback; + System::Clock::Milliseconds32 mLongPressDelayMillis{}; + System::Clock::Milliseconds32 mLongPressDurationMillis{}; + System::Clock::Milliseconds32 mMultiPressPressedTimeMillis{}; + System::Clock::Milliseconds32 mMultiPressReleasedTimeMillis{}; + uint8_t mMultiPressNumPresses{ 1 }; + uint8_t mIdleButtonId{ 0 }; + uint8_t mPressedButtonId{ 1 }; + EndpointId mEndpointId{ 1 }; + + Mode mMode{ Mode::kModeLongPress }; + State mState{ State::kIdle }; +}; + +} // namespace app +} // namespace chip diff --git a/scripts/tests/run_python_test.py b/scripts/tests/run_python_test.py index 7d7500c10f5a11..91ee73e00d0e8d 100755 --- a/scripts/tests/run_python_test.py +++ b/scripts/tests/run_python_test.py @@ -169,7 +169,8 @@ def main_impl(app: str, factoryreset: bool, factoryreset_app_only: bool, app_arg app_args = [app] + shlex.split(app_args) logging.info(f"Execute: {app_args}") app_process = subprocess.Popen( - app_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0) + app_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0) + app_process.stdin.close() app_pid = app_process.pid DumpProgramOutputToQueue( log_cooking_threads, Fore.GREEN + "APP " + Style.RESET_ALL, app_process, stream_output, log_queue) @@ -192,7 +193,8 @@ def main_impl(app: str, factoryreset: bool, factoryreset_app_only: bool, app_arg logging.info(f"Execute: {final_script_command}") test_script_process = subprocess.Popen( - final_script_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + final_script_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + test_script_process.stdin.close() DumpProgramOutputToQueue(log_cooking_threads, Fore.GREEN + "TEST" + Style.RESET_ALL, test_script_process, stream_output, log_queue) diff --git a/src/python_testing/TC_SWTCH.py b/src/python_testing/TC_SWTCH.py new file mode 100644 index 00000000000000..867897ec54ec9d --- /dev/null +++ b/src/python_testing/TC_SWTCH.py @@ -0,0 +1,290 @@ +# +# Copyright (c) 2023 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. + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --endpoint 3 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto --PICS src/app/tests/suites/certification/ci-pics-values +# === END CI TEST ARGUMENTS === + +import json +import logging +import queue +import time +from typing import Any + +import chip.clusters as Clusters +from chip.clusters import ClusterObjects as ClusterObjects +from chip.clusters.Attribute import EventReadResult, TypedAttributePath +from matter_testing_support import (AttributeValue, ClusterAttributeChangeAccumulator, EventChangeCallback, MatterBaseTest, + async_test_body, default_matter_test_main) +from mobly import asserts + +logger = logging.getLogger(__name__) + + +class TC_SwitchTests(MatterBaseTest): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def desc_TC_SWTCH_2_4(self) -> str: + """Returns a description of this test""" + return "[TC-SWTCH-2.4] Momentary Switch Long Press Verification" + + def pics_TC_SWTCH_2_4(self): + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["SWTCH.S", "SWTCH.S.F01"] + + # def steps_TC_SWTCH_2_4(self) -> list[TestStep]: + # steps = [ + # TestStep("0", "Commissioning, already done", is_commissioning=True), + # # TODO: fill when test is done + # ] + + # return steps + + def _send_named_pipe_command(self, command_dict: dict[str, Any]): + app_pid = self.matter_test_config.app_pid + if app_pid == 0: + asserts.fail("The --app-pid flag must be set when usage of button simulation named pipe is required (e.g. CI)") + + app_pipe = f"/tmp/chip_all_clusters_fifo_{app_pid}" + command = json.dumps(command_dict) + + # Sends an out-of-band command to the sample app + with open(app_pipe, "w") as outfile: + logging.info(f"Sending named pipe command to {app_pipe}: '{command}'") + outfile.write(command + "\n") + # Delay for pipe command to be processed (otherwise tests may be flaky). + time.sleep(0.1) + + def _use_button_simulator(self) -> bool: + return self.check_pics("PICS_SDK_CI_ONLY") or self.user_params.get("use_button_simulator", False) + + def _ask_for_switch_idle(self): + if not self._use_button_simulator(): + self.wait_for_user_input(prompt_msg="Ensure switch is idle") + + def _ask_for_long_press(self, endpoint_id: int, pressed_position: int): + if not self._use_button_simulator(): + self.wait_for_user_input( + prompt_msg=f"Press switch position {pressed_position} for a long time (around 5 seconds) on the DUT, then release it.") + else: + command_dict = {"Name": "SimulateActionSwitchLongPress", "EndpointId": endpoint_id, + "ButtonId": pressed_position, "LongPressDelayMillis": 5000, "LongPressDurationMillis": 5500} + self._send_named_pipe_command(command_dict) + + def _placeholder_for_step(self, step_id: str): + # TODO: Global search an replace of `self._placeholder_for_step` with `self.step` when done. + logging.info(f"Step {step_id}") + pass + + def _placeholder_for_skip(self, step_id: str): + logging.info(f"Skipped step {step_id}") + + def _await_sequence_of_reports(self, report_queue: queue.Queue, endpoint_id: int, attribute: TypedAttributePath, sequence: list[Any], timeout_sec: float): + start_time = time.time() + elapsed = 0.0 + time_remaining = timeout_sec + + sequence_idx = 0 + actual_values = [] + + while time_remaining > 0: + expected_value = sequence[sequence_idx] + logging.info(f"Expecting value {expected_value} for attribute {attribute} on endpoint {endpoint_id}") + try: + item: AttributeValue = report_queue.get(block=True, timeout=time_remaining) + + # Track arrival of all values for the given attribute. + if item.endpoint_id == endpoint_id and item.attribute == attribute: + actual_values.append(item.value) + + if item.value == expected_value: + logging.info(f"Got expected attribute change {sequence_idx+1}/{len(sequence)} for attribute {attribute}") + sequence_idx += 1 + else: + asserts.assert_equal(item.value, expected_value, + msg="Did not get expected attribute value in correct sequence.") + + # We are done waiting when we have accumulated all results. + if sequence_idx == len(sequence): + logging.info("Got all attribute changes, done waiting.") + return + except queue.Empty: + # No error, we update timeouts and keep going + pass + + elapsed = time.time() - start_time + time_remaining = timeout_sec - elapsed + + asserts.fail(f"Did not get full sequence {sequence} in {timeout_sec:.1f} seconds. Got {actual_values} before time-out.") + + def _await_sequence_of_events(self, event_queue: queue.Queue, endpoint_id: int, sequence: list[ClusterObjects.ClusterEvent], timeout_sec: float): + start_time = time.time() + elapsed = 0.0 + time_remaining = timeout_sec + + sequence_idx = 0 + actual_events = [] + + while time_remaining > 0: + logging.info(f"Expecting event {sequence[sequence_idx]} on endpoint {endpoint_id}") + try: + item: EventReadResult = event_queue.get(block=True, timeout=time_remaining) + expected_event = sequence[sequence_idx] + event_data = item.Data + + if item.Header.EndpointId == endpoint_id and item.Header.ClusterId == event_data.cluster_id: + actual_events.append(event_data) + + if event_data == expected_event: + logging.info(f"Got expected Event {sequence_idx+1}/{len(sequence)}: {event_data}") + sequence_idx += 1 + else: + asserts.assert_equal(event_data, expected_event, msg="Did not get expected event in correct sequence.") + + # We are done waiting when we have accumulated all results. + if sequence_idx == len(sequence): + logging.info("Got all expected events, done waiting.") + return + except queue.Empty: + # No error, we update timeouts and keep going + pass + + elapsed = time.time() - start_time + time_remaining = timeout_sec - elapsed + + asserts.fail(f"Did not get full sequence {sequence} in {timeout_sec:.1f} seconds. Got {actual_events} before time-out.") + + def _expect_no_events_for_cluster(self, event_queue: queue.Queue, endpoint_id: int, expected_cluster: ClusterObjects.Cluster, timeout_sec: float): + start_time = time.time() + elapsed = 0.0 + time_remaining = timeout_sec + + logging.info(f"Waiting {timeout_sec:.1f} seconds for no more events for cluster {expected_cluster} on endpoint {endpoint_id}") + while time_remaining > 0: + try: + item: EventReadResult = event_queue.get(block=True, timeout=time_remaining) + event_data = item.Data + + if item.Header.EndpointId == endpoint_id and item.Header.ClusterId == event_data.cluster_id and item.Header.ClusterId == expected_cluster.id: + asserts.fail(f"Got Event {event_data} when we expected no further events for {expected_cluster}") + except queue.Empty: + # No error, we update timeouts and keep going + pass + + elapsed = time.time() - start_time + time_remaining = timeout_sec - elapsed + + logging.info(f"Successfully waited for no further events on {expected_cluster} for {elapsed:.1f} seconds") + + @async_test_body + async def test_TC_SWTCH_2_4(self): + # TODO: Make this come from PIXIT + switch_pressed_position = 1 + post_prompt_settle_delay_seconds = 10.0 + + # Commission DUT - already done + + # Read feature map to set bool markers + cluster = Clusters.Objects.Switch + feature_map = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.FeatureMap) + + has_ms_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitch) != 0 + has_msr_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchRelease) != 0 + has_msl_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchLongPress) != 0 + has_as_feature = (feature_map & cluster.Bitmaps.Feature.kActionSwitch) != 0 + # has_msm_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchMultiPress) != 0 + + if not has_ms_feature: + logging.info("Skipping rest of test: SWTCH.S.F01(MS) feature not present") + self.skip_all_remaining_steps("2") + + endpoint_id = self.matter_test_config.endpoint + + # Step 1: Set up subscription to all Switch cluster events + self._placeholder_for_step("1") + event_listener = EventChangeCallback(cluster) + attrib_listener = ClusterAttributeChangeAccumulator(cluster) + await event_listener.start(self.default_controller, self.dut_node_id, endpoint=endpoint_id) + await attrib_listener.start(self.default_controller, self.dut_node_id, endpoint=endpoint_id) + + # Step 2: Operator does not operate switch on the DUT + self._placeholder_for_step("2") + self._ask_for_switch_idle() + + # Step 3: TH reads the CurrentPosition attribute from the DUT + self._placeholder_for_step("3") + + # Verify that the value is 0 + current_position = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.CurrentPosition) + asserts.assert_equal(current_position, 0) + + # Step 4a: Operator operates switch (keep pressed for long time, e.g. 5 seconds) on the DUT, the release it + self._placeholder_for_step("4a") + self._ask_for_long_press(endpoint_id, switch_pressed_position) + + # Step 4b: TH expects report of CurrentPosition 1, followed by a report of Current Position 0. + self._placeholder_for_step("4b") + logging.info( + f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for CurrentPosition to go {switch_pressed_position}, then 0.") + self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.CurrentPosition, sequence=[ + switch_pressed_position, 0], timeout_sec=post_prompt_settle_delay_seconds) + + # Step 4c: TH expects at least InitialPress with NewPosition = 1 + self._placeholder_for_step("4c") + logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for InitialPress event.") + expected_events = [cluster.Events.InitialPress(newPosition=switch_pressed_position)] + self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id, + sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds) + + # Step 4d: For MSL/AS, expect to see LongPress/LongRelease in that order + if not has_msl_feature and not has_as_feature: + logging.info("Skipping Step 4d due to missing MSL and AS features") + self._placeholder_for_skip("4d") + else: + # Steb 4d: TH expects report of LongPress, LongRelease in that order. + self._placeholder_for_step("4d") + logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for LongPress then LongRelease.") + expected_events = [] + expected_events.append(cluster.Events.LongPress(newPosition=switch_pressed_position)) + expected_events.append(cluster.Events.LongRelease(previousPosition=switch_pressed_position)) + self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id, + sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds) + + # Step 4e: For MS & (!MSL & !AS & !MSR), expect no further events for 10 seconds. + if not has_msl_feature and not has_as_feature and not has_msr_feature: + self._placeholder_for_step("4e") + self._expect_no_events_for_cluster(event_queue=event_listener.event_queue, + endpoint_id=endpoint_id, expected_cluster=cluster, timeout_sec=10.0) + + # Step 4f: For MSR & not MSL, expect to see ShortRelease. + if not has_msl_feature and has_msr_feature: + self._placeholder_for_step("4f") + expected_events = [cluster.Events.ShortRelease(previousPosition=switch_pressed_position)] + self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id, + sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 90ffe5e018ca43..e3c8683acd52ae 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -34,7 +34,7 @@ from dataclasses import dataclass, field from datetime import datetime, timedelta, timezone from enum import Enum -from typing import List, Optional, Tuple +from typing import Any, List, Optional, Tuple from chip.tlv import float32, uint @@ -231,19 +231,22 @@ def name(self) -> str: class EventChangeCallback: - def __init__(self, expected_cluster: ClusterObjects): + def __init__(self, expected_cluster: ClusterObjects.Cluster): """This class creates a queue to store received event callbacks, that can be checked by the test script expected_cluster: is the cluster from which the events are expected """ self._q = queue.Queue() self._expected_cluster = expected_cluster - async def start(self, dev_ctrl, node_id: int, endpoint: int): + async def start(self, dev_ctrl, node_id: int, endpoint: int, fabric_filtered: bool = False, min_interval_sec: int = 0, max_interval_sec: int = 30) -> Any: """This starts a subscription for events on the specified node_id and endpoint. The cluster is specified when the class instance is created.""" + urgent = True self._subscription = await dev_ctrl.ReadEvent(node_id, - events=[(endpoint, self._expected_cluster, True)], reportInterval=(1, 5), - fabricFiltered=False, keepSubscriptions=True, autoResubscribe=False) + events=[(endpoint, self._expected_cluster, urgent)], reportInterval=( + min_interval_sec, max_interval_sec), + fabricFiltered=fabric_filtered, keepSubscriptions=True, autoResubscribe=False) self._subscription.SetEventUpdateCallback(self.__call__) + return self._subscription def __call__(self, res: EventReadResult, transaction: SubscriptionTransaction): """This is the subscription callback when an event is received. @@ -265,6 +268,10 @@ def wait_for_event_report(self, expected_event: ClusterObjects.ClusterEvent, tim asserts.assert_equal(res.Header.EventId, expected_event.event_id, "Expected event ID not found in event report") return res.Data + @property + def event_queue(self) -> queue.Queue: + return self._q + class AttributeChangeCallback: def __init__(self, expected_attribute: ClusterObjects.ClusterAttributeDescriptor): @@ -299,6 +306,45 @@ def wait_for_report(self): asserts.fail("[AttributeChangeCallback] Attribute {expected_attribute} not found in returned report") +@dataclass +class AttributeValue: + endpoint_id: int + attribute: ClusterObjects.ClusterAttributeDescriptor + value: Any + + +class ClusterAttributeChangeAccumulator: + def __init__(self, expected_cluster: ClusterObjects.Cluster): + self._q = queue.Queue() + self._expected_cluster = expected_cluster + self._subscription = None + + async def start(self, dev_ctrl, node_id: int, endpoint: int, fabric_filtered: bool = False, min_interval_sec: int = 0, max_interval_sec: int = 30) -> Any: + """This starts a subscription for attributes on the specified node_id and endpoint. The cluster is specified when the class instance is created.""" + self._subscription = await dev_ctrl.ReadAttribute( + nodeid=node_id, + attributes=[(endpoint, self._expected_cluster)], + reportInterval=(min_interval_sec, max_interval_sec), + fabricFiltered=fabric_filtered, + keepSubscriptions=True + ) + self._subscription.SetAttributeUpdateCallback(self.__call__) + return self._subscription + + def __call__(self, path: TypedAttributePath, transaction: SubscriptionTransaction): + """This is the subscription callback when an attribute report is received. + It checks the report is from the expected_cluster and then posts it into the queue for later processing.""" + if path.ClusterType == self._expected_cluster: + data = transaction.GetAttribute(path) + value = AttributeValue(endpoint_id=path.Path.EndpointId, attribute=path.AttributeType, value=data) + logging.info(f"Got subscription report for {path.AttributeType}: {data}") + self._q.put(value) + + @property + def attribute_queue(self) -> queue.Queue: + return self._q + + class InternalTestRunnerHooks(TestRunnerHooks): def start(self, count: int): @@ -680,7 +726,7 @@ def get_test_steps(self, test: str) -> list[TestStep]: return [TestStep(1, "Run entire test")] if steps is None else steps def get_defined_test_steps(self, test: str) -> list[TestStep]: - steps_name = 'steps_' + test[5:] + steps_name = f'steps_{test.removeprefix("test_")}' try: fn = getattr(self, steps_name) return fn() @@ -700,7 +746,7 @@ def get_test_pics(self, test: str) -> list[str]: return [] if pics is None else pics def _get_defined_pics(self, test: str) -> list[TestStep]: - steps_name = 'pics_' + test[5:] + steps_name = f'pics_{test.removeprefix("test_")}' try: fn = getattr(self, steps_name) return fn() @@ -720,7 +766,7 @@ def get_test_desc(self, test: str) -> str: ex: 133.1.1. [TC-ACL-1.1] Global attributes ''' - desc_name = 'desc_' + test[5:] + desc_name = f'desc_{test.removeprefix("test_")}' try: fn = getattr(self, desc_name) return fn() @@ -1110,7 +1156,7 @@ def get_setup_payload_info(self) -> List[SetupPayloadInfo]: def wait_for_user_input(self, prompt_msg: str, prompt_msg_placeholder: str = "Submit anything to continue", - default_value: str = "y") -> str: + default_value: str = "y") -> Optional[str]: """Ask for user input and wait for it. Args: @@ -1119,13 +1165,19 @@ def wait_for_user_input(self, default_value (str, optional): TH UI prompt default value. Defaults to "y". Returns: - str: User input + str: User input or none if input is closed. """ if self.runner_hook: self.runner_hook.show_prompt(msg=prompt_msg, placeholder=prompt_msg_placeholder, default_value=default_value) - return input(f'{prompt_msg.removesuffix(chr(10))}\n') + logging.info("========= USER PROMPT =========") + logging.info(f">>> {prompt_msg.rstrip()} (press enter to confirm)") + try: + return input() + except EOFError: + logging.info("========= EOF on STDIN =========") + return None def generate_mobly_test_config(matter_test_config: MatterTestConfig): From 571fcd114970726aea28d67b39088a0fae24dd3e Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Thu, 25 Jul 2024 13:36:41 -0400 Subject: [PATCH 02/17] Declare some global items for future testing (#34509) Co-authored-by: Andrei Litvin --- .../zcl/data-model/chip/global-structs.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/app/zap-templates/zcl/data-model/chip/global-structs.xml b/src/app/zap-templates/zcl/data-model/chip/global-structs.xml index 54b4f69bc93bb8..c68c4aa1d000d7 100644 --- a/src/app/zap-templates/zcl/data-model/chip/global-structs.xml +++ b/src/app/zap-templates/zcl/data-model/chip/global-structs.xml @@ -31,4 +31,25 @@ TODO: Make these structures global rather than defining them for each cluster. + + + + + + + + + + + + + + + + + + From 4423b3a139a7b5862480894b87b88c5f3cf75bd9 Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:01:27 -0400 Subject: [PATCH 03/17] =?UTF-8?q?[LevelControl]=20Implemented=20the=20Q=20?= =?UTF-8?q?quality=20logic=20for=20the=20CurrentLevel=20a=E2=80=A6=20(#344?= =?UTF-8?q?88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implemented the Quiete reporting quality logic for the CurrentLevel and RemainingTime attributes * Restyled by clang-format * use c++ struct rather than c struct format * add cluster-building-blocks to the data model public dep --------- Co-authored-by: Restyled.io --- src/app/chip_data_model.gni | 1 + .../clusters/level-control/level-control.cpp | 198 ++++++++++++------ 2 files changed, 130 insertions(+), 69 deletions(-) diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 90b5bd1cfec3f3..b436f46cb7cb1f 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -414,6 +414,7 @@ template("chip_data_model") { ":${_data_model_name}_zapgen", "${chip_root}/src/access", "${chip_root}/src/app", + "${chip_root}/src/app/cluster-building-blocks", "${chip_root}/src/app/common:attribute-type", "${chip_root}/src/app/common:cluster-objects", "${chip_root}/src/app/common:enums", diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index 3f15620181dfd0..814436c39e179a 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include using namespace chip; +using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::LevelControl; using chip::Protocols::InteractionModel::Status; @@ -85,7 +87,7 @@ struct CallbackScheduleState // when called consecutively }; -typedef struct +struct EmberAfLevelControlState { CommandId commandId; uint8_t moveToLevel; @@ -98,23 +100,24 @@ typedef struct uint32_t transitionTimeMs; uint32_t elapsedTimeMs; CallbackScheduleState callbackSchedule; -} EmberAfLevelControlState; + QuieterReportingAttribute quietCurrentLevel{ DataModel::NullNullable }; + QuieterReportingAttribute quietRemainingTime{ DataModel::MakeNullable(0) }; +}; static EmberAfLevelControlState stateTable[kLevelControlStateTableSize]; static EmberAfLevelControlState * getState(EndpointId endpoint); static Status moveToLevelHandler(EndpointId endpoint, CommandId commandId, uint8_t level, - app::DataModel::Nullable transitionTimeDs, - chip::Optional> optionsMask, + DataModel::Nullable transitionTimeDs, chip::Optional> optionsMask, chip::Optional> optionsOverride, uint16_t storedLevel); -static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, MoveModeEnum moveMode, - app::DataModel::Nullable rate, chip::Optional> optionsMask, +static void moveHandler(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, MoveModeEnum moveMode, + DataModel::Nullable rate, chip::Optional> optionsMask, chip::Optional> optionsOverride); -static void stepHandler(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, StepModeEnum stepMode, - uint8_t stepSize, app::DataModel::Nullable transitionTimeDs, +static void stepHandler(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, StepModeEnum stepMode, + uint8_t stepSize, DataModel::Nullable transitionTimeDs, chip::Optional> optionsMask, chip::Optional> optionsOverride); -static void stopHandler(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +static void stopHandler(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, chip::Optional> optionsMask, chip::Optional> optionsOverride); static void setOnOffValue(EndpointId endpoint, bool onOff); @@ -122,6 +125,9 @@ static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs); static bool shouldExecuteIfOff(EndpointId endpoint, CommandId commandId, chip::Optional> optionsMask, chip::Optional> optionsOverride); +static Status SetCurrentLevelQuietReport(EndpointId endpoint, EmberAfLevelControlState * state, + DataModel::Nullable newValue, bool isStartOrEndOfTransition); + #if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl { @@ -162,7 +168,7 @@ class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl { using AttributeValuePair = ScenesManagement::Structs::AttributeValuePairStruct::Type; - app::DataModel::Nullable level; + DataModel::Nullable level; VerifyOrReturnError(Status::Success == Attributes::CurrentLevel::Get(endpoint, level), CHIP_ERROR_READ_FAILED); AttributeValuePair pairs[kLevelMaxScenableAttributes]; @@ -177,7 +183,7 @@ class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl } else { - pairs[0].valueUnsigned8.SetValue(app::NumericAttributeTraits::kNullValue); + pairs[0].valueUnsigned8.SetValue(NumericAttributeTraits::kNullValue); } size_t attributeCount = 1; if (LevelControlHasFeature(endpoint, LevelControl::Feature::kFrequency)) @@ -189,7 +195,7 @@ class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl attributeCount++; } - app::DataModel::List attributeValueList(pairs, attributeCount); + DataModel::List attributeValueList(pairs, attributeCount); return EncodeAttributeValueList(attributeValueList, serializedBytes); } @@ -203,7 +209,7 @@ class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, scenes::TransitionTimeMs timeMs) override { - app::DataModel::DecodableList attributeValueList; + DataModel::DecodableList attributeValueList; ReturnErrorOnFailure(DecodeAttributeValueList(serializedBytes, attributeValueList)); @@ -245,15 +251,15 @@ class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl EmberAfLevelControlState * state = getState(endpoint); if (level < state->minLevel || level > state->maxLevel) { - chip::app::NumericAttributeTraits::SetNull(level); + NumericAttributeTraits::SetNull(level); } - if (!app::NumericAttributeTraits::IsNullValue(level)) + if (!NumericAttributeTraits::IsNullValue(level)) { CommandId command = LevelControlHasFeature(endpoint, LevelControl::Feature::kOnOff) ? Commands::MoveToLevelWithOnOff::Id : Commands::MoveToLevel::Id; - moveToLevelHandler(endpoint, command, level, app::DataModel::MakeNullable(static_cast(timeMs / 100)), + moveToLevelHandler(endpoint, command, level, DataModel::MakeNullable(static_cast(timeMs / 100)), chip::Optional>(), chip::Optional>(), INVALID_STORED_LEVEL); } @@ -363,18 +369,68 @@ static void reallyUpdateCoupledColorTemp(EndpointId endpoint) } #endif // IGNORE_LEVEL_CONTROL_CLUSTER_OPTIONS && MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP +/* + * @brief + * This function is used to update the current level attribute + * while respecting it's defined quiet reporting quality: + * The attribute will be reported: + * - At most once per second, or + * - At the start of the movement/transition, or + * - At the end of the movement/transition, or + * - When it changes from null to any other value and vice versa. + * + * @param endpoint: endpoint on which the currentLevel attribute must be updated. + * @param state: LevelControlState struct of this given endpoint. + * @param newValue: Value to update the attribute with + * @param isStartOrEndOfTransition: Boolean that indicate whether the update is occuring at the start or end of a level transition + * @return Success in setting the attribute value or the IM error code for the failure. + */ +static Status SetCurrentLevelQuietReport(EndpointId endpoint, EmberAfLevelControlState * state, + DataModel::Nullable newValue, bool isStartOrEndOfTransition) +{ + AttributeDirtyState dirtyState; + MarkAttributeDirty markDirty = MarkAttributeDirty::kNo; + auto now = System::SystemClock().GetMonotonicTimestamp(); + + if (isStartOrEndOfTransition) + { + // At the start or end of the movement/transition we must report + auto predicate = [](const decltype(state->quietCurrentLevel)::SufficientChangePredicateCandidate &) -> bool { + return true; + }; + dirtyState = state->quietCurrentLevel.SetValue(newValue, now, predicate); + } + else + { + // During transtions, reports should be at most once per second + System::Clock::Milliseconds64 reportInterval = + std::max(System::Clock::Milliseconds64(1000), System::Clock::Milliseconds64(state->transitionTimeMs / 4)); + auto predicate = state->quietCurrentLevel.GetPredicateForSufficientTimeSinceLastDirty(reportInterval); + dirtyState = state->quietCurrentLevel.SetValue(newValue, now, predicate); + } + + if (dirtyState == AttributeDirtyState::kMustReport) + { + markDirty = MarkAttributeDirty::kIfChanged; + } + return Attributes::CurrentLevel::Set(endpoint, state->quietCurrentLevel.value(), markDirty); +} + void emberAfLevelControlClusterServerTickCallback(EndpointId endpoint) { EmberAfLevelControlState * state = getState(endpoint); Status status; - app::DataModel::Nullable currentLevel; + DataModel::Nullable currentLevel; const auto callbackStartTimestamp = System::SystemClock().GetMonotonicTimestamp(); + bool isTransitionStart = false; + bool isTransitionEnd = false; if (state == nullptr) { return; } + isTransitionStart = (state->elapsedTimeMs == 0); state->elapsedTimeMs += state->eventDurationMs; // Read the attribute; print error message and return if it can't be read @@ -412,7 +468,9 @@ void emberAfLevelControlClusterServerTickCallback(EndpointId endpoint) ChipLogDetail(Zcl, " to %d ", currentLevel.Value()); ChipLogDetail(Zcl, "(diff %c1)", state->increasing ? '+' : '-'); - status = Attributes::CurrentLevel::Set(endpoint, currentLevel); + // Are we at the requested level? + isTransitionEnd = (currentLevel.Value() == state->moveToLevel); + status = SetCurrentLevelQuietReport(endpoint, state, currentLevel, (isTransitionStart || isTransitionEnd)); if (status != Status::Success) { ChipLogProgress(Zcl, "ERR: writing current level %x", to_underlying(status)); @@ -423,8 +481,7 @@ void emberAfLevelControlClusterServerTickCallback(EndpointId endpoint) updateCoupledColorTemp(endpoint); - // Are we at the requested level? - if (currentLevel.Value() == state->moveToLevel) + if (isTransitionEnd) { if (state->commandId == Commands::MoveToLevelWithOnOff::Id || state->commandId == Commands::MoveWithOnOff::Id || state->commandId == Commands::StepWithOnOff::Id) @@ -478,11 +535,20 @@ static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs) // This is done to ensure that the attribute, in tenths of a second, only // goes to zero when the remaining time in milliseconds is actually zero. uint16_t remainingTimeDs = static_cast((remainingTimeMs + 99) / 100); - Status status = LevelControl::Attributes::RemainingTime::Set(endpoint, remainingTimeDs); - if (status != Status::Success) + auto markDirty = MarkAttributeDirty::kNo; + auto state = getState(endpoint); + auto now = System::SystemClock().GetMonotonicTimestamp(); + + // Establish the quiet report condition for the RemainingTime Attribute + // The quiet report is determined by the previously set policies: + // - kMarkDirtyOnChangeToFromZero : When the value changes from 0 to any other value and vice versa, or + // - kMarkDirtyOnIncrement : When the value increases. + if (state->quietRemainingTime.SetValue(remainingTimeDs, now) == AttributeDirtyState::kMustReport) { - ChipLogProgress(Zcl, "ERR: writing remaining time %x", to_underlying(status)); + markDirty = MarkAttributeDirty::kIfChanged; } + + Attributes::RemainingTime::Set(endpoint, state->quietRemainingTime.value().ValueOr(0), markDirty); } #endif // IGNORE_LEVEL_CONTROL_CLUSTER_LEVEL_CONTROL_REMAINING_TIME } @@ -583,7 +649,7 @@ static bool shouldExecuteIfOff(EndpointId endpoint, CommandId commandId, chip::O return true; } -bool emberAfLevelControlClusterMoveToLevelCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterMoveToLevelCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::MoveToLevel::DecodableType & commandData) { MATTER_TRACE_SCOPE("MoveToLevel", "LevelControl"); @@ -629,8 +695,7 @@ chip::scenes::SceneHandler * GetSceneHandler() } // namespace LevelControlServer -bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(app::CommandHandler * commandObj, - const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::MoveToLevelWithOnOff::DecodableType & commandData) { MATTER_TRACE_SCOPE("MoveToLevelWithOnOff", "LevelControl"); @@ -660,7 +725,7 @@ bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(app::CommandHandler return true; } -bool emberAfLevelControlClusterMoveCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterMoveCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::Move::DecodableType & commandData) { MATTER_TRACE_SCOPE("Move", "LevelControl"); @@ -685,7 +750,7 @@ bool emberAfLevelControlClusterMoveCallback(app::CommandHandler * commandObj, co return true; } -bool emberAfLevelControlClusterMoveWithOnOffCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterMoveWithOnOffCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::MoveWithOnOff::DecodableType & commandData) { MATTER_TRACE_SCOPE("MoveWithOnOff", "LevelControl"); @@ -710,7 +775,7 @@ bool emberAfLevelControlClusterMoveWithOnOffCallback(app::CommandHandler * comma return true; } -bool emberAfLevelControlClusterStepCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterStepCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::Step::DecodableType & commandData) { MATTER_TRACE_SCOPE("Step", "LevelControl"); @@ -736,7 +801,7 @@ bool emberAfLevelControlClusterStepCallback(app::CommandHandler * commandObj, co return true; } -bool emberAfLevelControlClusterStepWithOnOffCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterStepWithOnOffCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::StepWithOnOff::DecodableType & commandData) { MATTER_TRACE_SCOPE("StepWithOnOff", "LevelControl"); @@ -762,7 +827,7 @@ bool emberAfLevelControlClusterStepWithOnOffCallback(app::CommandHandler * comma return true; } -bool emberAfLevelControlClusterStopCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterStopCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::Stop::DecodableType & commandData) { MATTER_TRACE_SCOPE("Stop", "LevelControl"); @@ -775,7 +840,7 @@ bool emberAfLevelControlClusterStopCallback(app::CommandHandler * commandObj, co return true; } -bool emberAfLevelControlClusterStopWithOnOffCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +bool emberAfLevelControlClusterStopWithOnOffCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const Commands::StopWithOnOff::DecodableType & commandData) { MATTER_TRACE_SCOPE("StopWithOnOff", "LevelControl"); @@ -788,12 +853,11 @@ bool emberAfLevelControlClusterStopWithOnOffCallback(app::CommandHandler * comma } static Status moveToLevelHandler(EndpointId endpoint, CommandId commandId, uint8_t level, - app::DataModel::Nullable transitionTimeDs, - chip::Optional> optionsMask, + DataModel::Nullable transitionTimeDs, chip::Optional> optionsMask, chip::Optional> optionsOverride, uint16_t storedLevel) { EmberAfLevelControlState * state = getState(endpoint); - app::DataModel::Nullable currentLevel; + DataModel::Nullable currentLevel; uint8_t actualStepSize; if (state == nullptr) @@ -916,11 +980,9 @@ static Status moveToLevelHandler(EndpointId endpoint, CommandId commandId, uint8 // The duration between events will be the transition time divided by the // distance we must move. - state->eventDurationMs = state->transitionTimeMs / std::max(static_cast(1u), actualStepSize); - state->elapsedTimeMs = 0; - - state->storedLevel = storedLevel; - + state->eventDurationMs = state->transitionTimeMs / std::max(static_cast(1u), actualStepSize); + state->elapsedTimeMs = 0; + state->storedLevel = storedLevel; state->callbackSchedule.runTime = System::Clock::Milliseconds32(0); #ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT @@ -946,14 +1008,14 @@ static Status moveToLevelHandler(EndpointId endpoint, CommandId commandId, uint8 return Status::Success; } -static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, MoveModeEnum moveMode, - app::DataModel::Nullable rate, chip::Optional> optionsMask, +static void moveHandler(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, MoveModeEnum moveMode, + DataModel::Nullable rate, chip::Optional> optionsMask, chip::Optional> optionsOverride) { Status status; uint8_t difference; EmberAfLevelControlState * state; - app::DataModel::Nullable currentLevel; + DataModel::Nullable currentLevel; EndpointId endpoint = commandPath.mEndpointId; CommandId commandId = commandPath.mCommandId; @@ -983,7 +1045,7 @@ static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCom // Otherwise, move as fast as possible if (rate.IsNull()) { - app::DataModel::Nullable defaultMoveRate; + DataModel::Nullable defaultMoveRate; status = Attributes::DefaultMoveRate::Get(endpoint, defaultMoveRate); if (status != Status::Success || defaultMoveRate.IsNull()) { @@ -1078,8 +1140,7 @@ static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCom state->elapsedTimeMs = 0; // storedLevel is not used for Move commands. - state->storedLevel = INVALID_STORED_LEVEL; - + state->storedLevel = INVALID_STORED_LEVEL; state->callbackSchedule.runTime = System::Clock::Milliseconds32(0); // The setup was successful, so mark the new state as active and return. @@ -1090,13 +1151,13 @@ static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCom commandObj->AddStatus(commandPath, status); } -static void stepHandler(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, StepModeEnum stepMode, - uint8_t stepSize, app::DataModel::Nullable transitionTimeDs, +static void stepHandler(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, StepModeEnum stepMode, + uint8_t stepSize, DataModel::Nullable transitionTimeDs, chip::Optional> optionsMask, chip::Optional> optionsOverride) { Status status; EmberAfLevelControlState * state; - app::DataModel::Nullable currentLevel; + DataModel::Nullable currentLevel; EndpointId endpoint = commandPath.mEndpointId; CommandId commandId = commandPath.mCommandId; @@ -1226,8 +1287,7 @@ static void stepHandler(app::CommandHandler * commandObj, const app::ConcreteCom state->elapsedTimeMs = 0; // storedLevel is not used for Step commands - state->storedLevel = INVALID_STORED_LEVEL; - + state->storedLevel = INVALID_STORED_LEVEL; state->callbackSchedule.runTime = System::Clock::Milliseconds32(0); // The setup was successful, so mark the new state as active and return. @@ -1238,14 +1298,13 @@ static void stepHandler(app::CommandHandler * commandObj, const app::ConcreteCom commandObj->AddStatus(commandPath, status); } -static void stopHandler(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, +static void stopHandler(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, chip::Optional> optionsMask, chip::Optional> optionsOverride) { - EndpointId endpoint = commandPath.mEndpointId; - CommandId commandId = commandPath.mCommandId; - + EndpointId endpoint = commandPath.mEndpointId; + CommandId commandId = commandPath.mCommandId; EmberAfLevelControlState * state = getState(endpoint); - Status status; + Status status = Status::Success; if (state == nullptr) { @@ -1255,14 +1314,13 @@ static void stopHandler(app::CommandHandler * commandObj, const app::ConcreteCom if (!shouldExecuteIfOff(endpoint, commandId, optionsMask, optionsOverride)) { - status = Status::Success; goto send_default_response; } // Cancel any currently active command. cancelEndpointTimerCallback(endpoint); + SetCurrentLevelQuietReport(endpoint, state, state->quietCurrentLevel.value(), true /*isStartOrEndOfTransition*/); writeRemainingTime(endpoint, 0); - status = Status::Success; send_default_response: commandObj->AddStatus(commandPath, status); @@ -1272,9 +1330,9 @@ static void stopHandler(app::CommandHandler * commandObj, const app::ConcreteCom // Quotes are from table 3.46. void emberAfOnOffClusterLevelControlEffectCallback(EndpointId endpoint, bool newValue) { - app::DataModel::Nullable resolvedLevel; - app::DataModel::Nullable temporaryCurrentLevelCache; - app::DataModel::Nullable transitionTime; + DataModel::Nullable resolvedLevel; + DataModel::Nullable temporaryCurrentLevelCache; + DataModel::Nullable transitionTime; uint16_t currentOnOffTransitionTime; Status status; @@ -1355,7 +1413,7 @@ void emberAfOnOffClusterLevelControlEffectCallback(EndpointId endpoint, bool new { // If newValue is OnOff::Commands::On::Id... // "Set CurrentLevel to minimum level allowed for the device." - status = Attributes::CurrentLevel::Set(endpoint, minimumLevelAllowedForTheDevice); + status = SetCurrentLevelQuietReport(endpoint, state, minimumLevelAllowedForTheDevice, true /*isStartOrEndOfTransition*/); if (status != Status::Success) { ChipLogProgress(Zcl, "ERR: reading current level %x", to_underlying(status)); @@ -1398,6 +1456,9 @@ void emberAfLevelControlClusterServerInitCallback(EndpointId endpoint) return; } + state->quietRemainingTime.policy() + .Set(QuieterReportingPolicyEnum::kMarkDirtyOnIncrement) + .Set(QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero); state->minLevel = MATTER_DM_PLUGIN_LEVEL_CONTROL_MINIMUM_LEVEL; state->maxLevel = MATTER_DM_PLUGIN_LEVEL_CONTROL_MAXIMUM_LEVEL; @@ -1419,7 +1480,7 @@ void emberAfLevelControlClusterServerInitCallback(EndpointId endpoint) } } - app::DataModel::Nullable currentLevel; + DataModel::Nullable currentLevel; Status status = Attributes::CurrentLevel::Get(endpoint, currentLevel); if (status == Status::Success) { @@ -1440,7 +1501,7 @@ void emberAfLevelControlClusterServerInitCallback(EndpointId endpoint) // 0xFF Work Around ZAP Can't set default value to NULL // https://github.com/project-chip/zap/issues/354 - app::DataModel::Nullable startUpCurrentLevel; + DataModel::Nullable startUpCurrentLevel; status = Attributes::StartUpCurrentLevel::Get(endpoint, startUpCurrentLevel); if (status == Status::Success) { @@ -1470,25 +1531,24 @@ void emberAfLevelControlClusterServerInitCallback(EndpointId endpoint) } } // Otherwise Set the CurrentLevel attribute to its previous value which was already fetch above - - Attributes::CurrentLevel::Set(endpoint, currentLevel); + SetCurrentLevelQuietReport(endpoint, state, currentLevel, true /*isStartOrEndOfTransition*/); } } #endif // IGNORE_LEVEL_CONTROL_CLUSTER_START_UP_CURRENT_LEVEL // In any case, we make sure that the respects min/max if (currentLevel.IsNull() || currentLevel.Value() < state->minLevel) { - Attributes::CurrentLevel::Set(endpoint, state->minLevel); + SetCurrentLevelQuietReport(endpoint, state, state->minLevel, true /*isStartOrEndOfTransition*/); } else if (currentLevel.Value() > state->maxLevel) { - Attributes::CurrentLevel::Set(endpoint, state->maxLevel); + SetCurrentLevelQuietReport(endpoint, state, state->maxLevel, true /*isStartOrEndOfTransition*/); } } #if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS // Registers Scene handlers for the level control cluster on the server - app::Clusters::ScenesManagement::ScenesServer::Instance().RegisterSceneHandler(endpoint, LevelControlServer::GetSceneHandler()); + Clusters::ScenesManagement::ScenesServer::Instance().RegisterSceneHandler(endpoint, LevelControlServer::GetSceneHandler()); #endif // defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS emberAfPluginLevelControlClusterServerPostInitCallback(endpoint); From 2a607350ccea2e6666a250b7591cc2545ed1b450 Mon Sep 17 00:00:00 2001 From: C Freeman Date: Thu, 25 Jul 2024 15:15:56 -0400 Subject: [PATCH 04/17] Revert thermostat stuff breaking tot (#34518) * Revert "update tests and thermostat server cluster for new constraints for LocalTemperatureCalibration and MinSetpointDeadBand (#34474)" This reverts commit 335ac96cdde78fd81d69d6fb451427e769b7f413. * Revert "update constraints for LocalTemperatureCalibration and MinSetpointDeadBand attributes (#34473)" This reverts commit 21a5bd6a402b699c0d64283918e266092a771bd1. --- .../all-clusters-app/app-templates/endpoint_config.h | 2 +- src/app/clusters/thermostat-server/thermostat-server.cpp | 2 +- src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml | 6 +++--- .../zcl/data-model/chip/thermostat-cluster.xml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h index a77bd74f11f267..f2c082b1d0d4a1 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h @@ -307,7 +307,7 @@ { (uint16_t) 0xBB8, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxHeatSetpointLimit */ \ { (uint16_t) 0x640, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MinCoolSetpointLimit */ \ { (uint16_t) 0xC80, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxCoolSetpointLimit */ \ - { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x7F }, /* MinSetpointDeadBand */ \ + { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x19 }, /* MinSetpointDeadBand */ \ { (uint16_t) 0x4, (uint16_t) 0x0, (uint16_t) 0x5 }, /* ControlSequenceOfOperation */ \ { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x9 }, /* SystemMode */ \ \ diff --git a/src/app/clusters/thermostat-server/thermostat-server.cpp b/src/app/clusters/thermostat-server/thermostat-server.cpp index e802a9201f33dc..c650a30c871989 100644 --- a/src/app/clusters/thermostat-server/thermostat-server.cpp +++ b/src/app/clusters/thermostat-server/thermostat-server.cpp @@ -409,7 +409,7 @@ MatterThermostatClusterServerPreAttributeChangedCallback(const app::ConcreteAttr requested = *value; if (!AutoSupported) return imcode::UnsupportedAttribute; - if (requested < 0 || requested > 127) + if (requested < 0 || requested > 25) return imcode::InvalidValue; return imcode::Success; } diff --git a/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml b/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml index 4558b08745a949..faf34fdea43e92 100644 --- a/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_TSTAT_2_1.yaml @@ -243,8 +243,8 @@ tests: response: constraints: type: int8s - minValue: -127 - maxValue: 127 + minValue: -25 + maxValue: 25 - label: "Step 13a: TH reads attribute OccupiedCoolingSetpoint from the DUT" PICS: TSTAT.S.F01 && TSTAT.S.A0017 && TSTAT.S.A0018 @@ -426,7 +426,7 @@ tests: constraints: type: int8s minValue: 0 - maxValue: 127 + maxValue: 25 - label: "Step 22: TH reads the RemoteSensing attribute from the DUT" PICS: TSTAT.S.A001a diff --git a/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml index c2979487e45ae3..91a89497d7c8cc 100644 --- a/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml @@ -337,7 +337,7 @@ limitations under the License. - + LocalTemperatureCalibration @@ -361,7 +361,7 @@ limitations under the License. MaxCoolSetpointLimit - + MinSetpointDeadBand From 5ea06ea871002f256f3dc5f41c9de566592d4b50 Mon Sep 17 00:00:00 2001 From: Alex Tsitsiura Date: Thu, 25 Jul 2024 22:25:54 +0300 Subject: [PATCH 05/17] [Telink] Update Docker image (Zephyr update) (#34503) --- integrations/docker/images/base/chip-build/version | 2 +- integrations/docker/images/stage-2/chip-build-telink/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index 8a1624d292e305..ba77442b28dc23 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -65 : [nrfconnect] Update nRF Connect SDK version. +66 : [Telink] Update Docker image (Zephyr update) diff --git a/integrations/docker/images/stage-2/chip-build-telink/Dockerfile b/integrations/docker/images/stage-2/chip-build-telink/Dockerfile index 66d5eccdc0d3a1..bea580245e8639 100644 --- a/integrations/docker/images/stage-2/chip-build-telink/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-telink/Dockerfile @@ -18,7 +18,7 @@ RUN set -x \ && : # last line # Setup Zephyr -ARG ZEPHYR_REVISION=ab81a585fca6a83b30e1f4e58a021113d6a3acb8 +ARG ZEPHYR_REVISION=ef7bfc2214602ecf237332b71e6a2bdd69205fbd WORKDIR /opt/telink/zephyrproject RUN set -x \ && python3 -m pip install --break-system-packages -U --no-cache-dir west \ From b74057ee9cbc6f510996ffa5ec09fa25023bee91 Mon Sep 17 00:00:00 2001 From: Pradip De Date: Thu, 25 Jul 2024 12:46:52 -0700 Subject: [PATCH 06/17] Add TransportPayloadCapability flag for GetConnectedDevices and bubble (#34450) up the flag to the wrapper IM Python APIs. Add python script binding methods for LargePayload tests --to check if session allows large payload. --to close the underlying TCP connection. --to check if the session is active. --- .../ChipDeviceController-ScriptBinding.cpp | 61 +++++++++++- src/controller/python/chip/ChipDeviceCtrl.py | 99 +++++++++++++++---- src/python_testing/matter_testing_support.py | 6 +- 3 files changed, 144 insertions(+), 22 deletions(-) diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index d4603efe05e469..d9b557bb62be67 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -213,7 +213,8 @@ PyChipError pychip_DeviceCommissioner_CloseBleConnection(chip::Controller::Devic const char * pychip_Stack_StatusReportToString(uint32_t profileId, uint16_t statusCode); PyChipError pychip_GetConnectedDeviceByNodeId(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId, - chip::Controller::Python::PyObject * context, DeviceAvailableFunc callback); + chip::Controller::Python::PyObject * context, DeviceAvailableFunc callback, + int transportPayloadCapability); PyChipError pychip_FreeOperationalDeviceProxy(chip::OperationalDeviceProxy * deviceProxy); PyChipError pychip_GetLocalSessionId(chip::OperationalDeviceProxy * deviceProxy, uint16_t * localSessionId); PyChipError pychip_GetNumSessionsToPeer(chip::OperationalDeviceProxy * deviceProxy, uint32_t * numSessions); @@ -239,6 +240,13 @@ void pychip_Storage_ShutdownAdapter(chip::Controller::Python::StorageAdapter * s // ICD // void pychip_CheckInDelegate_SetOnCheckInCompleteCallback(PyChipCheckInDelegate::OnCheckInCompleteCallback * callback); + +// +// LargePayload and TCP +PyChipError pychip_SessionAllowsLargePayload(chip::OperationalDeviceProxy * deviceProxy, bool * allowsLargePayload); +PyChipError pychip_IsSessionOverTCPConnection(chip::OperationalDeviceProxy * deviceProxy, bool * isSessionOverTCP); +PyChipError pychip_IsActiveSession(chip::OperationalDeviceProxy * deviceProxy, bool * isActiveSession); +PyChipError pychip_CloseTCPConnectionWithPeer(chip::OperationalDeviceProxy * deviceProxy); } void * pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObject * context, @@ -807,11 +815,58 @@ struct GetDeviceCallbacks } // anonymous namespace PyChipError pychip_GetConnectedDeviceByNodeId(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId, - chip::Controller::Python::PyObject * context, DeviceAvailableFunc callback) + chip::Controller::Python::PyObject * context, DeviceAvailableFunc callback, + int transportPayloadCapability) { VerifyOrReturnError(devCtrl != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); auto * callbacks = new GetDeviceCallbacks(context, callback); - return ToPyChipError(devCtrl->GetConnectedDevice(nodeId, &callbacks->mOnSuccess, &callbacks->mOnFailure)); + return ToPyChipError(devCtrl->GetConnectedDevice(nodeId, &callbacks->mOnSuccess, &callbacks->mOnFailure, + static_cast(transportPayloadCapability))); +} + +PyChipError pychip_SessionAllowsLargePayload(chip::OperationalDeviceProxy * deviceProxy, bool * allowsLargePayload) +{ + VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_MISSING_SECURE_SESSION)); + VerifyOrReturnError(allowsLargePayload != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); + + *allowsLargePayload = deviceProxy->GetSecureSession().Value()->AsSecureSession()->AllowsLargePayload(); + + return ToPyChipError(CHIP_NO_ERROR); +} + +PyChipError pychip_IsSessionOverTCPConnection(chip::OperationalDeviceProxy * deviceProxy, bool * isSessionOverTCP) +{ + VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_MISSING_SECURE_SESSION)); + VerifyOrReturnError(isSessionOverTCP != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); + + *isSessionOverTCP = deviceProxy->GetSecureSession().Value()->AsSecureSession()->GetTCPConnection() != nullptr; + + return ToPyChipError(CHIP_NO_ERROR); +} + +PyChipError pychip_IsActiveSession(chip::OperationalDeviceProxy * deviceProxy, bool * isActiveSession) +{ + VerifyOrReturnError(isActiveSession != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); + + *isActiveSession = false; + if (deviceProxy->GetSecureSession().HasValue()) + { + *isActiveSession = deviceProxy->GetSecureSession().Value()->AsSecureSession()->IsActiveSession(); + } + + return ToPyChipError(CHIP_NO_ERROR); +} + +PyChipError pychip_CloseTCPConnectionWithPeer(chip::OperationalDeviceProxy * deviceProxy) +{ + VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_MISSING_SECURE_SESSION)); + VerifyOrReturnError(deviceProxy->GetSecureSession().Value()->AsSecureSession()->AllowsLargePayload(), + ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); + + deviceProxy->GetExchangeManager()->GetSessionManager()->TCPDisconnect( + deviceProxy->GetSecureSession().Value()->AsSecureSession()->GetTCPConnection(), /* shouldAbort = */ false); + + return ToPyChipError(CHIP_NO_ERROR); } PyChipError pychip_FreeOperationalDeviceProxy(chip::OperationalDeviceProxy * deviceProxy) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 0e568803b1e523..91c83e8954fa37 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -84,6 +84,16 @@ _ChipDeviceController_IterateDiscoveredCommissionableNodesFunct = CFUNCTYPE(None, c_char_p, c_size_t) +# Defines for the transport payload types to use to select the suitable +# underlying transport of the session. +# class TransportPayloadCapability(ctypes.c_int): + + +class TransportPayloadCapability(ctypes.c_int): + MRP_PAYLOAD = 0 + LARGE_PAYLOAD = 1 + MRP_OR_TCP_PAYLOAD = 2 + @dataclass class CommissioningParameters: @@ -371,6 +381,53 @@ def attestationChallenge(self) -> bytes: return bytes(buf) + @property + def sessionAllowsLargePayload(self) -> bool: + self._dmLib.pychip_SessionAllowsLargePayload.argtypes = [ctypes.c_void_p, POINTER(ctypes.c_bool)] + self._dmLib.pychip_SessionAllowsLargePayload.restype = PyChipError + + supportsLargePayload = ctypes.c_bool(False) + + builtins.chipStack.Call( + lambda: self._dmLib.pychip_SessionAllowsLargePayload(self._deviceProxy, pointer(supportsLargePayload)) + ).raise_on_error() + + return supportsLargePayload.value + + @property + def isSessionOverTCPConnection(self) -> bool: + self._dmLib.pychip_IsSessionOverTCPConnection.argtypes = [ctypes.c_void_p, POINTER(ctypes.c_bool)] + self._dmLib.pychip_IsSessionOverTCPConnection.restype = PyChipError + + isSessionOverTCP = ctypes.c_bool(False) + + builtins.chipStack.Call( + lambda: self._dmLib.pychip_IsSessionOverTCPConnection(self._deviceProxy, pointer(isSessionOverTCP)) + ).raise_on_error() + + return isSessionOverTCP.value + + @property + def isActiveSession(self) -> bool: + self._dmLib.pychip_IsActiveSession.argtypes = [ctypes.c_void_p, POINTER(ctypes.c_bool)] + self._dmLib.pychip_IsActiveSession.restype = PyChipError + + isActiveSession = ctypes.c_bool(False) + + builtins.chipStack.Call( + lambda: self._dmLib.pychip_IsActiveSession(self._deviceProxy, pointer(isActiveSession)) + ).raise_on_error() + + return isActiveSession.value + + def closeTCPConnectionWithPeer(self): + self._dmLib.pychip_CloseTCPConnectionWithPeer.argtypes = [ctypes.c_void_p] + self._dmLib.pychip_CloseTCPConnectionWithPeer.restype = PyChipError + + builtins.chipStack.Call( + lambda: self._dmLib.pychip_CloseTCPConnectionWithPeer(self._deviceProxy) + ).raise_on_error() + DiscoveryFilterType = discovery.FilterType DiscoveryType = discovery.DiscoveryType @@ -906,7 +963,7 @@ async def FindOrEstablishPASESession(self, setupCode: str, nodeid: int, timeoutM if res.is_success: return DeviceProxyWrapper(returnDevice, DeviceProxyWrapper.DeviceProxyType.COMMISSIONEE, self._dmLib) - def GetConnectedDeviceSync(self, nodeid, allowPASE=True, timeoutMs: int = None): + def GetConnectedDeviceSync(self, nodeid, allowPASE=True, timeoutMs: int = None, payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Gets an OperationalDeviceProxy or CommissioneeDeviceProxy for the specified Node. nodeId: Target's Node ID @@ -943,7 +1000,7 @@ def deviceAvailable(self, device, err): closure = DeviceAvailableClosure() ctypes.pythonapi.Py_IncRef(ctypes.py_object(closure)) self._ChipStack.Call(lambda: self._dmLib.pychip_GetConnectedDeviceByNodeId( - self.devCtrl, nodeid, ctypes.py_object(closure), _DeviceAvailableCallback), + self.devCtrl, nodeid, ctypes.py_object(closure), _DeviceAvailableCallback, payloadCapability), timeoutMs).raise_on_error() # The callback might have been received synchronously (during self._ChipStack.Call()). @@ -975,7 +1032,8 @@ async def WaitForActive(self, nodeid, *, timeoutSeconds=30.0, stayActiveDuration await WaitForCheckIn(ScopedNodeId(nodeid, self._fabricIndex), timeoutSeconds=timeoutSeconds) return await self.SendCommand(nodeid, 0, Clusters.IcdManagement.Commands.StayActiveRequest(stayActiveDuration=stayActiveDurationMs)) - async def GetConnectedDevice(self, nodeid, allowPASE: bool = True, timeoutMs: int = None): + async def GetConnectedDevice(self, nodeid, allowPASE: bool = True, timeoutMs: int = None, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Gets an OperationalDeviceProxy or CommissioneeDeviceProxy for the specified Node. nodeId: Target's Node ID @@ -1020,7 +1078,7 @@ def deviceAvailable(self, device, err): closure = DeviceAvailableClosure(eventLoop, future) ctypes.pythonapi.Py_IncRef(ctypes.py_object(closure)) await self._ChipStack.CallAsync(lambda: self._dmLib.pychip_GetConnectedDeviceByNodeId( - self.devCtrl, nodeid, ctypes.py_object(closure), _DeviceAvailableCallback), + self.devCtrl, nodeid, ctypes.py_object(closure), _DeviceAvailableCallback, payloadCapability), timeoutMs) # The callback might have been received synchronously (during self._ChipStack.CallAsync()). @@ -1124,7 +1182,8 @@ async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None, timedRequestTimeoutMs: typing.Union[None, int] = None, interactionTimeoutMs: typing.Union[None, int] = None, busyWaitMs: typing.Union[None, int] = None, - suppressResponse: typing.Union[None, bool] = None): + suppressResponse: typing.Union[None, bool] = None, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Send a cluster-object encapsulated command to a node and get returned a future that can be awaited upon to receive the response. If a valid responseType is passed in, that will be used to de-serialize the object. If not, @@ -1144,7 +1203,7 @@ async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects. eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs, payloadCapability=payloadCapability) res = await ClusterCommand.SendCommand( future, eventLoop, responseType, device.deviceProxy, ClusterCommand.CommandPath( EndpointId=endpoint, @@ -1158,7 +1217,8 @@ async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects. async def SendBatchCommands(self, nodeid: int, commands: typing.List[ClusterCommand.InvokeRequestInfo], timedRequestTimeoutMs: typing.Optional[int] = None, interactionTimeoutMs: typing.Optional[int] = None, busyWaitMs: typing.Optional[int] = None, - suppressResponse: typing.Optional[bool] = None): + suppressResponse: typing.Optional[bool] = None, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Send a batch of cluster-object encapsulated commands to a node and get returned a future that can be awaited upon to receive the responses. If a valid responseType is passed in, that will be used to de-serialize the object. If not, @@ -1186,7 +1246,7 @@ async def SendBatchCommands(self, nodeid: int, commands: typing.List[ClusterComm eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs, payloadCapability=payloadCapability) res = await ClusterCommand.SendBatchCommands( future, eventLoop, device.deviceProxy, commands, @@ -1215,7 +1275,8 @@ def SendGroupCommand(self, groupid: int, payload: ClusterObjects.ClusterCommand, async def WriteAttribute(self, nodeid: int, attributes: typing.List[typing.Tuple[int, ClusterObjects.ClusterAttributeDescriptor]], timedRequestTimeoutMs: typing.Union[None, int] = None, - interactionTimeoutMs: typing.Union[None, int] = None, busyWaitMs: typing.Union[None, int] = None): + interactionTimeoutMs: typing.Union[None, int] = None, busyWaitMs: typing.Union[None, int] = None, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Write a list of attributes on a target node. @@ -1237,7 +1298,7 @@ async def WriteAttribute(self, nodeid: int, eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs, payloadCapability=payloadCapability) attrs = [] for v in attributes: @@ -1396,7 +1457,8 @@ async def Read(self, nodeid: int, attributes: typing.List[typing.Union[ ]] = None, eventNumberFilter: typing.Optional[int] = None, returnClusterObject: bool = False, reportInterval: typing.Tuple[int, int] = None, - fabricFiltered: bool = True, keepSubscriptions: bool = False, autoResubscribe: bool = True): + fabricFiltered: bool = True, keepSubscriptions: bool = False, autoResubscribe: bool = True, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Read a list of attributes and/or events from a target node @@ -1456,7 +1518,7 @@ async def Read(self, nodeid: int, attributes: typing.List[typing.Union[ eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = await self.GetConnectedDevice(nodeid) + device = await self.GetConnectedDevice(nodeid, payloadCapability=payloadCapability) attributePaths = [self._parseAttributePathTuple( v) for v in attributes] if attributes else None clusterDataVersionFilters = [self._parseDataVersionFilterTuple( @@ -1487,7 +1549,8 @@ async def ReadAttribute(self, nodeid: int, attributes: typing.List[typing.Union[ ]], dataVersionFilters: typing.List[typing.Tuple[int, typing.Type[ClusterObjects.Cluster], int]] = None, returnClusterObject: bool = False, reportInterval: typing.Tuple[int, int] = None, - fabricFiltered: bool = True, keepSubscriptions: bool = False, autoResubscribe: bool = True): + fabricFiltered: bool = True, keepSubscriptions: bool = False, autoResubscribe: bool = True, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Read a list of attributes from a target node, this is a wrapper of DeviceController.Read() @@ -1547,7 +1610,8 @@ async def ReadAttribute(self, nodeid: int, attributes: typing.List[typing.Union[ reportInterval=reportInterval, fabricFiltered=fabricFiltered, keepSubscriptions=keepSubscriptions, - autoResubscribe=autoResubscribe) + autoResubscribe=autoResubscribe, + payloadCapability=payloadCapability) if isinstance(res, ClusterAttribute.SubscriptionTransaction): return res else: @@ -1569,7 +1633,8 @@ async def ReadEvent(self, nodeid: int, events: typing.List[typing.Union[ fabricFiltered: bool = True, reportInterval: typing.Tuple[int, int] = None, keepSubscriptions: bool = False, - autoResubscribe: bool = True): + autoResubscribe: bool = True, + payloadCapability: int = TransportPayloadCapability.MRP_PAYLOAD): ''' Read a list of events from a target node, this is a wrapper of DeviceController.Read() @@ -1616,7 +1681,7 @@ async def ReadEvent(self, nodeid: int, events: typing.List[typing.Union[ ''' res = await self.Read(nodeid=nodeid, events=events, eventNumberFilter=eventNumberFilter, fabricFiltered=fabricFiltered, reportInterval=reportInterval, keepSubscriptions=keepSubscriptions, - autoResubscribe=autoResubscribe) + autoResubscribe=autoResubscribe, payloadCapability=payloadCapability) if isinstance(res, ClusterAttribute.SubscriptionTransaction): return res else: @@ -1764,7 +1829,7 @@ def _InitLib(self): self._dmLib.pychip_ScriptDevicePairingDelegate_SetExpectingPairingComplete.restype = PyChipError self._dmLib.pychip_GetConnectedDeviceByNodeId.argtypes = [ - c_void_p, c_uint64, py_object, _DeviceAvailableCallbackFunct] + c_void_p, c_uint64, py_object, _DeviceAvailableCallbackFunct, c_int] self._dmLib.pychip_GetConnectedDeviceByNodeId.restype = PyChipError self._dmLib.pychip_FreeOperationalDeviceProxy.argtypes = [ diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index e3c8683acd52ae..11b1dfb01c0760 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -928,7 +928,8 @@ async def read_single_attribute_expect_error( async def send_single_cmd( self, cmd: Clusters.ClusterObjects.ClusterCommand, dev_ctrl: ChipDeviceCtrl = None, node_id: int = None, endpoint: int = None, - timedRequestTimeoutMs: typing.Union[None, int] = None) -> object: + timedRequestTimeoutMs: typing.Union[None, int] = None, + payloadCapability: int = ChipDeviceCtrl.TransportPayloadCapability.MRP_PAYLOAD) -> object: if dev_ctrl is None: dev_ctrl = self.default_controller if node_id is None: @@ -936,7 +937,8 @@ async def send_single_cmd( if endpoint is None: endpoint = self.matter_test_config.endpoint - result = await dev_ctrl.SendCommand(nodeid=node_id, endpoint=endpoint, payload=cmd, timedRequestTimeoutMs=timedRequestTimeoutMs) + result = await dev_ctrl.SendCommand(nodeid=node_id, endpoint=endpoint, payload=cmd, timedRequestTimeoutMs=timedRequestTimeoutMs, + payloadCapability=payloadCapability) return result async def send_test_event_triggers(self, eventTrigger: int, enableKey: bytes = None): From ba949bff52cd3cf382e56916d14dcae57bc764bc Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 25 Jul 2024 16:03:15 -0400 Subject: [PATCH 07/17] Remove no-longer-used MTRDevice logic for truncating data version lists (#34183) * Remove no-longer-used MTRDevice logic for truncating data version lists After https://github.com/project-chip/connectedhomeip/pull/34111, ReadClient handles this logic itself, so the attempted truncation in MTRDevice was now dead code. * Address review comment. * Fix compile issues. * Address another review comment. * Address review comment. --- src/app/ReadClient.cpp | 22 ++++- src/darwin/Framework/CHIP/MTRDevice.mm | 132 ++++++++++--------------- 2 files changed, 74 insertions(+), 80 deletions(-) diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp index 470c875fbaac30..51adf6e8ddc143 100644 --- a/src/app/ReadClient.cpp +++ b/src/app/ReadClient.cpp @@ -403,6 +403,11 @@ CHIP_ERROR ReadClient::BuildDataVersionFilterList(DataVersionFilterIBs::Builder const Span & aDataVersionFilters, bool & aEncodedDataVersionList) { +#if CHIP_PROGRESS_LOGGING + size_t encodedFilterCount = 0; + size_t irrelevantFilterCount = 0; + size_t skippedFilterCount = 0; +#endif for (auto & filter : aDataVersionFilters) { VerifyOrReturnError(filter.IsValidDataVersionFilter(), CHIP_ERROR_INVALID_ARGUMENT); @@ -420,6 +425,9 @@ CHIP_ERROR ReadClient::BuildDataVersionFilterList(DataVersionFilterIBs::Builder if (!intersected) { +#if CHIP_PROGRESS_LOGGING + ++irrelevantFilterCount; +#endif continue; } @@ -428,19 +436,31 @@ CHIP_ERROR ReadClient::BuildDataVersionFilterList(DataVersionFilterIBs::Builder CHIP_ERROR err = EncodeDataVersionFilter(aDataVersionFilterIBsBuilder, filter); if (err == CHIP_NO_ERROR) { +#if CHIP_PROGRESS_LOGGING + ++encodedFilterCount; +#endif aEncodedDataVersionList = true; } else if (err == CHIP_ERROR_NO_MEMORY || err == CHIP_ERROR_BUFFER_TOO_SMALL) { // Packet is full, ignore the rest of the list aDataVersionFilterIBsBuilder.Rollback(backup); - return CHIP_NO_ERROR; +#if CHIP_PROGRESS_LOGGING + ssize_t nonSkippedFilterCount = &filter - aDataVersionFilters.data(); + skippedFilterCount = aDataVersionFilters.size() - static_cast(nonSkippedFilterCount); +#endif // CHIP_PROGRESS_LOGGING + break; } else { return err; } } + + ChipLogProgress(DataManagement, + "%lu data version filters provided, %lu not relevant, %lu encoded, %lu skipped due to lack of space", + static_cast(aDataVersionFilters.size()), static_cast(irrelevantFilterCount), + static_cast(encodedFilterCount), static_cast(skippedFilterCount)); return CHIP_NO_ERROR; } diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index 1c68d788943ce2..b8ef8694825e1f 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -2277,32 +2277,26 @@ - (void)_removeCachedAttribute:(NSNumber *)attributeID fromCluster:(MTRClusterPa [clusterData removeValueForAttribute:attributeID]; } -- (void)_createDataVersionFilterListFromDictionary:(NSDictionary *)dataVersions dataVersionFilterList:(DataVersionFilter **)dataVersionFilterList count:(size_t *)count sizeReduction:(size_t)sizeReduction +- (void)_createDataVersionFilterListFromDictionary:(NSDictionary *)dataVersions dataVersionFilterList:(DataVersionFilter **)dataVersionFilterList count:(size_t *)count { - size_t maxDataVersionFilterSize = dataVersions.count; + size_t dataVersionFilterSize = dataVersions.count; // Check if any filter list should be generated - if (!dataVersions.count || (maxDataVersionFilterSize <= sizeReduction)) { + if (dataVersionFilterSize == 0) { *count = 0; *dataVersionFilterList = nullptr; return; } - maxDataVersionFilterSize -= sizeReduction; - DataVersionFilter * dataVersionFilterArray = new DataVersionFilter[maxDataVersionFilterSize]; + DataVersionFilter * dataVersionFilterArray = new DataVersionFilter[dataVersionFilterSize]; size_t i = 0; for (MTRClusterPath * path in dataVersions) { NSNumber * dataVersionNumber = dataVersions[path]; - if (dataVersionNumber) { - dataVersionFilterArray[i++] = DataVersionFilter(static_cast(path.endpoint.unsignedShortValue), static_cast(path.cluster.unsignedLongValue), static_cast(dataVersionNumber.unsignedLongValue)); - } - if (i == maxDataVersionFilterSize) { - break; - } + dataVersionFilterArray[i++] = DataVersionFilter(static_cast(path.endpoint.unsignedShortValue), static_cast(path.cluster.unsignedLongValue), static_cast(dataVersionNumber.unsignedLongValue)); } *dataVersionFilterList = dataVersionFilterArray; - *count = maxDataVersionFilterSize; + *count = dataVersionFilterSize; } - (void)_setupConnectivityMonitoring @@ -2530,75 +2524,55 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason auto readClient = std::make_unique(InteractionModelEngine::GetInstance(), exchangeManager, clusterStateCache->GetBufferedCallback(), ReadClient::InteractionType::Subscribe); - // Subscribe with data version filter list and retry with smaller list if out of packet space - CHIP_ERROR err; - NSDictionary * dataVersions = [self _getCachedDataVersions]; - size_t dataVersionFilterListSizeReduction = 0; - for (;;) { - // Wildcard endpoint, cluster, attribute, event. - auto attributePath = std::make_unique(); - auto eventPath = std::make_unique(); - // We want to get event reports at the minInterval, not the maxInterval. - eventPath->mIsUrgentEvent = true; - ReadPrepareParams readParams(session.Value()); - - readParams.mMinIntervalFloorSeconds = 0; - // Select a max interval based on the device's claimed idle sleep interval. - auto idleSleepInterval = std::chrono::duration_cast( - session.Value()->GetRemoteMRPConfig().mIdleRetransTimeout); - - auto maxIntervalCeilingMin = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN); - if (idleSleepInterval < maxIntervalCeilingMin) { - idleSleepInterval = maxIntervalCeilingMin; - } - - auto maxIntervalCeilingMax = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX); - if (idleSleepInterval > maxIntervalCeilingMax) { - idleSleepInterval = maxIntervalCeilingMax; - } + // Wildcard endpoint, cluster, attribute, event. + auto attributePath = std::make_unique(); + auto eventPath = std::make_unique(); + // We want to get event reports at the minInterval, not the maxInterval. + eventPath->mIsUrgentEvent = true; + ReadPrepareParams readParams(session.Value()); + + readParams.mMinIntervalFloorSeconds = 0; + // Select a max interval based on the device's claimed idle sleep interval. + auto idleSleepInterval = std::chrono::duration_cast( + session.Value()->GetRemoteMRPConfig().mIdleRetransTimeout); + + auto maxIntervalCeilingMin = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN); + if (idleSleepInterval < maxIntervalCeilingMin) { + idleSleepInterval = maxIntervalCeilingMin; + } + + auto maxIntervalCeilingMax = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX); + if (idleSleepInterval > maxIntervalCeilingMax) { + idleSleepInterval = maxIntervalCeilingMax; + } #ifdef DEBUG - if (maxIntervalOverride.HasValue()) { - idleSleepInterval = maxIntervalOverride.Value(); - } -#endif - readParams.mMaxIntervalCeilingSeconds = static_cast(idleSleepInterval.count()); - - readParams.mpAttributePathParamsList = attributePath.get(); - readParams.mAttributePathParamsListSize = 1; - readParams.mpEventPathParamsList = eventPath.get(); - readParams.mEventPathParamsListSize = 1; - readParams.mKeepSubscriptions = true; - readParams.mIsFabricFiltered = false; - size_t dataVersionFilterListSize = 0; - DataVersionFilter * dataVersionFilterList; - [self _createDataVersionFilterListFromDictionary:dataVersions dataVersionFilterList:&dataVersionFilterList count:&dataVersionFilterListSize sizeReduction:dataVersionFilterListSizeReduction]; - readParams.mDataVersionFilterListSize = dataVersionFilterListSize; - readParams.mpDataVersionFilterList = dataVersionFilterList; - attributePath.release(); - eventPath.release(); - - // TODO: Change from local filter list generation to rehydrating ClusterStateCache ot take advantage of existing filter list sorting algorithm - - // SendAutoResubscribeRequest cleans up the params, even on failure. - err = readClient->SendAutoResubscribeRequest(std::move(readParams)); - if (err == CHIP_NO_ERROR) { - break; - } - - // If error is not a "no memory" issue, then break and go through regular resubscribe logic - if (err != CHIP_ERROR_NO_MEMORY) { - break; - } - - // If "no memory" error is not caused by data version filter list, break as well - if (!dataVersionFilterListSize) { - break; - } - - // Now "no memory" could mean subscribe request packet space ran out. Reduce size and try again immediately - dataVersionFilterListSizeReduction++; + if (maxIntervalOverride.HasValue()) { + idleSleepInterval = maxIntervalOverride.Value(); } +#endif + readParams.mMaxIntervalCeilingSeconds = static_cast(idleSleepInterval.count()); + + readParams.mpAttributePathParamsList = attributePath.get(); + readParams.mAttributePathParamsListSize = 1; + readParams.mpEventPathParamsList = eventPath.get(); + readParams.mEventPathParamsListSize = 1; + readParams.mKeepSubscriptions = true; + readParams.mIsFabricFiltered = false; + + // Subscribe with data version filter list from our cache. + size_t dataVersionFilterListSize = 0; + DataVersionFilter * dataVersionFilterList; + [self _createDataVersionFilterListFromDictionary:[self _getCachedDataVersions] dataVersionFilterList:&dataVersionFilterList count:&dataVersionFilterListSize]; + + readParams.mDataVersionFilterListSize = dataVersionFilterListSize; + readParams.mpDataVersionFilterList = dataVersionFilterList; + attributePath.release(); + eventPath.release(); + + // TODO: Change from local filter list generation to rehydrating ClusterStateCache to take advantage of existing filter list sorting algorithm + // SendAutoResubscribeRequest cleans up the params, even on failure. + CHIP_ERROR err = readClient->SendAutoResubscribeRequest(std::move(readParams)); if (err != CHIP_NO_ERROR) { NSError * error = [MTRError errorForCHIPErrorCode:err logContext:self]; MTR_LOG_ERROR("%@ SendAutoResubscribeRequest error %@", self, error); @@ -2610,7 +2584,7 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason return; } - MTR_LOG("%@ Subscribe with data version list size %lu, reduced by %lu", self, static_cast(dataVersions.count), static_cast(dataVersionFilterListSizeReduction)); + MTR_LOG("%@ Subscribe with data version list size %lu", self, static_cast(dataVersionFilterListSize)); // Callback and ClusterStateCache and ReadClient will be deleted // when OnDone is called. From 434b3f855473853d6daeb3f00cb0f23c02c3a8b4 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Thu, 25 Jul 2024 17:51:32 -0400 Subject: [PATCH 08/17] Add fabric sync related changed into bridge device info cluster (#34336) --- .../placeholder/linux/apps/app1/config.matter | 11 +++ .../placeholder/linux/apps/app2/config.matter | 11 +++ .../chip/bridged-device-basic-information.xml | 14 ++++ .../data_model/controller-clusters.matter | 11 +++ .../chip/devicecontroller/ChipClusters.java | 16 ++++ .../devicecontroller/ChipEventStructs.java | 46 ++++++++++++ .../devicecontroller/ClusterIDMapping.java | 6 +- .../devicecontroller/ClusterInfoMapping.java | 12 +++ ...sicInformationClusterActiveChangedEvent.kt | 56 ++++++++++++++ .../chip/devicecontroller/cluster/files.gni | 1 + .../BridgedDeviceBasicInformationCluster.kt | 21 ++++++ ...sicInformationClusterActiveChangedEvent.kt | 56 ++++++++++++++ .../java/matter/controller/cluster/files.gni | 1 + .../CHIPEventTLVValueDecoder.cpp | 39 ++++++++++ .../python/chip/clusters/CHIPClusters.py | 6 ++ .../python/chip/clusters/Objects.py | 37 ++++++++++ .../CHIP/zap-generated/MTRBaseClusters.h | 13 ++++ .../CHIP/zap-generated/MTRBaseClusters.mm | 29 ++++++++ .../CHIP/zap-generated/MTRClusterConstants.h | 6 ++ .../CHIP/zap-generated/MTRClusters.h | 8 +- .../CHIP/zap-generated/MTRClusters.mm | 31 ++++++++ .../zap-generated/MTRCommandPayloadsObjc.h | 28 +++++++ .../zap-generated/MTRCommandPayloadsObjc.mm | 73 ++++++++++++++++++ .../MTRCommandPayloads_Internal.h | 6 ++ .../zap-generated/MTREventTLVValueDecoder.mm | 17 +++++ .../CHIP/zap-generated/MTRStructsObjc.h | 5 ++ .../CHIP/zap-generated/MTRStructsObjc.mm | 27 +++++++ .../app-common/zap-generated/callback.h | 6 ++ .../app-common/zap-generated/cluster-enums.h | 6 ++ .../zap-generated/cluster-objects.cpp | 65 +++++++++++++++- .../zap-generated/cluster-objects.h | 74 +++++++++++++++++++ .../app-common/zap-generated/ids/Commands.h | 10 +++ .../app-common/zap-generated/ids/Events.h | 4 + .../zap-generated/cluster/Commands.h | 44 ++++++++++- .../cluster/logging/DataModelLogger.cpp | 21 ++++++ .../cluster/logging/DataModelLogger.h | 2 + .../zap-generated/cluster/Commands.h | 52 +++++++++++++ 37 files changed, 865 insertions(+), 6 deletions(-) create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index 2f250369cd3c05..1955b363c01a4d 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -2320,6 +2320,10 @@ cluster BridgedDeviceBasicInformation = 57 { kFabric = 5; } + bitmap Feature : bitmap32 { + kBridgedICDSupport = 0x100000; + } + struct ProductAppearanceStruct { ProductFinishEnum finish = 0; nullable ColorEnum primaryColor = 1; @@ -2339,6 +2343,10 @@ cluster BridgedDeviceBasicInformation = 57 { boolean reachableNewValue = 0; } + info event ActiveChanged = 128 { + int32u promisedActiveDuration = 0; + } + readonly attribute optional char_string<32> vendorName = 1; readonly attribute optional vendor_id vendorID = 2; readonly attribute optional char_string<32> productName = 3; @@ -2361,6 +2369,9 @@ cluster BridgedDeviceBasicInformation = 57 { readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + /** The server SHALL attempt to keep the devices specified active for StayActiveDuration milliseconds when they are next active. */ + command KeepActive(): DefaultSuccess = 128; } /** This cluster exposes interactions with a switch device, for the purpose of using those interactions by other devices. diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index a68dc9ce2b63f2..8debe20800dc40 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -2277,6 +2277,10 @@ cluster BridgedDeviceBasicInformation = 57 { kFabric = 5; } + bitmap Feature : bitmap32 { + kBridgedICDSupport = 0x100000; + } + struct ProductAppearanceStruct { ProductFinishEnum finish = 0; nullable ColorEnum primaryColor = 1; @@ -2296,6 +2300,10 @@ cluster BridgedDeviceBasicInformation = 57 { boolean reachableNewValue = 0; } + info event ActiveChanged = 128 { + int32u promisedActiveDuration = 0; + } + readonly attribute optional char_string<32> vendorName = 1; readonly attribute optional vendor_id vendorID = 2; readonly attribute optional char_string<32> productName = 3; @@ -2318,6 +2326,9 @@ cluster BridgedDeviceBasicInformation = 57 { readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + /** The server SHALL attempt to keep the devices specified active for StayActiveDuration milliseconds when they are next active. */ + command KeepActive(): DefaultSuccess = 128; } /** This cluster exposes interactions with a switch device, for the purpose of using those interactions by other devices. diff --git a/src/app/zap-templates/zcl/data-model/chip/bridged-device-basic-information.xml b/src/app/zap-templates/zcl/data-model/chip/bridged-device-basic-information.xml index 702ea8754795b1..ff118a8a80c162 100644 --- a/src/app/zap-templates/zcl/data-model/chip/bridged-device-basic-information.xml +++ b/src/app/zap-templates/zcl/data-model/chip/bridged-device-basic-information.xml @@ -71,6 +71,12 @@ limitations under the License. true + + + + + + VendorName VendorID ProductName @@ -88,6 +94,10 @@ limitations under the License. UniqueID ProductAppearance + + The server SHALL attempt to keep the devices specified active for StayActiveDuration milliseconds when they are next active. + + The StartUp event SHALL be emitted by a Node as soon as reasonable after completing a boot or reboot process. @@ -102,6 +112,10 @@ limitations under the License. This event SHALL be generated when there is a change in the Reachable attribute. + + This event (when supported) SHALL be generated the next time a bridged device becomes active after a KeepActive command is received. + + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 6acf9fd8c4fb2f..39a4d56bfd69b8 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -2225,6 +2225,10 @@ cluster BridgedDeviceBasicInformation = 57 { kFabric = 5; } + bitmap Feature : bitmap32 { + kBridgedICDSupport = 0x100000; + } + struct ProductAppearanceStruct { ProductFinishEnum finish = 0; nullable ColorEnum primaryColor = 1; @@ -2244,6 +2248,10 @@ cluster BridgedDeviceBasicInformation = 57 { boolean reachableNewValue = 0; } + info event ActiveChanged = 128 { + int32u promisedActiveDuration = 0; + } + readonly attribute optional char_string<32> vendorName = 1; readonly attribute optional vendor_id vendorID = 2; readonly attribute optional char_string<32> productName = 3; @@ -2266,6 +2274,9 @@ cluster BridgedDeviceBasicInformation = 57 { readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + /** The server SHALL attempt to keep the devices specified active for StayActiveDuration milliseconds when they are next active. */ + command KeepActive(): DefaultSuccess = 128; } /** This cluster exposes interactions with a switch device, for the purpose of using those interactions by other devices. diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 66338f93c0b225..bbdc1dea185456 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -14963,6 +14963,22 @@ public long initWithDevice(long devicePtr, int endpointId) { return 0L; } + public void keepActive(DefaultClusterCallback callback) { + keepActive(callback, 0); + } + + public void keepActive(DefaultClusterCallback callback, int timedInvokeTimeoutMs) { + final long commandId = 128L; + + ArrayList elements = new ArrayList<>(); + StructType commandArgs = new StructType(elements); + invoke(new InvokeCallbackImpl(callback) { + @Override + public void onResponse(StructType invokeStructValue) { + callback.onSuccess(); + }}, commandId, commandArgs, timedInvokeTimeoutMs); + } + public interface ProductAppearanceAttributeCallback extends BaseAttributeCallback { void onSuccess(ChipStructs.BridgedDeviceBasicInformationClusterProductAppearanceStruct value); } diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java index 6ab2b64ce65000..e33980d8a6e7d9 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java @@ -1899,6 +1899,52 @@ public String toString() { return output.toString(); } } +public static class BridgedDeviceBasicInformationClusterActiveChangedEvent { + public Long promisedActiveDuration; + private static final long PROMISED_ACTIVE_DURATION_ID = 0L; + + public BridgedDeviceBasicInformationClusterActiveChangedEvent( + Long promisedActiveDuration + ) { + this.promisedActiveDuration = promisedActiveDuration; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(PROMISED_ACTIVE_DURATION_ID, new UIntType(promisedActiveDuration))); + + return new StructType(values); + } + + public static BridgedDeviceBasicInformationClusterActiveChangedEvent decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + Long promisedActiveDuration = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == PROMISED_ACTIVE_DURATION_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + promisedActiveDuration = castingValue.value(Long.class); + } + } + } + return new BridgedDeviceBasicInformationClusterActiveChangedEvent( + promisedActiveDuration + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("BridgedDeviceBasicInformationClusterActiveChangedEvent {\n"); + output.append("\tpromisedActiveDuration: "); + output.append(promisedActiveDuration); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} public static class SwitchClusterSwitchLatchedEvent { public Integer newPosition; private static final long NEW_POSITION_ID = 0L; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index 6959f3a3d83caa..72972b2554c102 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -4455,7 +4455,8 @@ public enum Event { StartUp(0L), ShutDown(1L), Leave(2L), - ReachableChanged(3L),; + ReachableChanged(3L), + ActiveChanged(128L),; private final long id; Event(long id) { this.id = id; @@ -4475,7 +4476,8 @@ public static Event value(long id) throws NoSuchFieldError { } } - public enum Command {; + public enum Command { + KeepActive(128L),; private final long id; Command(long id) { this.id = id; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 99bae94690439d..98a276983b8670 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -24028,6 +24028,18 @@ public Map> getCommandMap() { Map bridgedDeviceBasicInformationClusterInteractionInfoMap = new LinkedHashMap<>(); + Map bridgedDeviceBasicInformationkeepActiveCommandParams = new LinkedHashMap(); + InteractionInfo bridgedDeviceBasicInformationkeepActiveInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.BridgedDeviceBasicInformationCluster) cluster) + .keepActive((DefaultClusterCallback) callback + ); + }, + () -> new DelegatedDefaultClusterCallback(), + bridgedDeviceBasicInformationkeepActiveCommandParams + ); + bridgedDeviceBasicInformationClusterInteractionInfoMap.put("keepActive", bridgedDeviceBasicInformationkeepActiveInteractionInfo); + commandMap.put("bridgedDeviceBasicInformation", bridgedDeviceBasicInformationClusterInteractionInfoMap); Map switchClusterInteractionInfoMap = new LinkedHashMap<>(); diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt new file mode 100644 index 00000000000000..73be6ff7c1042e --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2023 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. + */ +package chip.devicecontroller.cluster.eventstructs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class BridgedDeviceBasicInformationClusterActiveChangedEvent(val promisedActiveDuration: ULong) { + override fun toString(): String = buildString { + append("BridgedDeviceBasicInformationClusterActiveChangedEvent {\n") + append("\tpromisedActiveDuration : $promisedActiveDuration\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_PROMISED_ACTIVE_DURATION), promisedActiveDuration) + endStructure() + } + } + + companion object { + private const val TAG_PROMISED_ACTIVE_DURATION = 0 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): BridgedDeviceBasicInformationClusterActiveChangedEvent { + tlvReader.enterStructure(tlvTag) + val promisedActiveDuration = + tlvReader.getULong(ContextSpecificTag(TAG_PROMISED_ACTIVE_DURATION)) + + tlvReader.exitContainer() + + return BridgedDeviceBasicInformationClusterActiveChangedEvent(promisedActiveDuration) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index f50c3e2c82b56e..90ce4a42ae206f 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -162,6 +162,7 @@ eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateClusterStateChangeEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterStartUpEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt index 73f0502017eee1..45adb1bb8f7820 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt @@ -23,6 +23,8 @@ import java.util.logging.Logger import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.transform import matter.controller.BooleanSubscriptionState +import matter.controller.InvokeRequest +import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest @@ -36,6 +38,7 @@ import matter.controller.WriteRequests import matter.controller.WriteResponse import matter.controller.cluster.structs.* import matter.controller.model.AttributePath +import matter.controller.model.CommandPath import matter.tlv.AnonymousTag import matter.tlv.TlvReader import matter.tlv.TlvWriter @@ -97,6 +100,24 @@ class BridgedDeviceBasicInformationCluster( object SubscriptionEstablished : AttributeListAttributeSubscriptionState() } + suspend fun keepActive(timedInvokeTimeout: Duration? = null) { + val commandId: UInt = 128u + + val tlvWriter = TlvWriter() + tlvWriter.startStructure(AnonymousTag) + tlvWriter.endStructure() + + val request: InvokeRequest = + InvokeRequest( + CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), + tlvPayload = tlvWriter.getEncoded(), + timedRequest = timedInvokeTimeout, + ) + + val response: InvokeResponse = controller.invoke(request) + logger.log(Level.FINE, "Invoke command succeeded: ${response}") + } + suspend fun readVendorNameAttribute(): String? { val ATTRIBUTE_ID: UInt = 1u diff --git a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt new file mode 100644 index 00000000000000..7713cb0faf07b3 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2023 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. + */ +package matter.controller.cluster.eventstructs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class BridgedDeviceBasicInformationClusterActiveChangedEvent(val promisedActiveDuration: UInt) { + override fun toString(): String = buildString { + append("BridgedDeviceBasicInformationClusterActiveChangedEvent {\n") + append("\tpromisedActiveDuration : $promisedActiveDuration\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_PROMISED_ACTIVE_DURATION), promisedActiveDuration) + endStructure() + } + } + + companion object { + private const val TAG_PROMISED_ACTIVE_DURATION = 0 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): BridgedDeviceBasicInformationClusterActiveChangedEvent { + tlvReader.enterStructure(tlvTag) + val promisedActiveDuration = + tlvReader.getUInt(ContextSpecificTag(TAG_PROMISED_ACTIVE_DURATION)) + + tlvReader.exitContainer() + + return BridgedDeviceBasicInformationClusterActiveChangedEvent(promisedActiveDuration) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index 856e286c2a2e7d..14ff82b93897cd 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -162,6 +162,7 @@ matter_eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateClusterStateChangeEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterActiveChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterStartUpEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/CommissionerControlClusterCommissioningRequestResultEvent.kt", diff --git a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp index 0dbed58b4b93d3..8d7826aed4d310 100644 --- a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp @@ -2159,6 +2159,45 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & return value; } + case Events::ActiveChanged::Id: { + Events::ActiveChanged::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value_promisedActiveDuration; + std::string value_promisedActiveDurationClassName = "java/lang/Long"; + std::string value_promisedActiveDurationCtorSignature = "(J)V"; + jlong jnivalue_promisedActiveDuration = static_cast(cppValue.promisedActiveDuration); + chip::JniReferences::GetInstance().CreateBoxedObject( + value_promisedActiveDurationClassName.c_str(), value_promisedActiveDurationCtorSignature.c_str(), + jnivalue_promisedActiveDuration, value_promisedActiveDuration); + + jclass activeChangedStructClass; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipEventStructs$BridgedDeviceBasicInformationClusterActiveChangedEvent", + activeChangedStructClass); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Could not find class ChipEventStructs$BridgedDeviceBasicInformationClusterActiveChangedEvent"); + return nullptr; + } + + jmethodID activeChangedStructCtor; + err = chip::JniReferences::GetInstance().FindMethod(env, activeChangedStructClass, "", "(Ljava/lang/Long;)V", + &activeChangedStructCtor); + if (err != CHIP_NO_ERROR || activeChangedStructCtor == nullptr) + { + ChipLogError(Zcl, + "Could not find ChipEventStructs$BridgedDeviceBasicInformationClusterActiveChangedEvent constructor"); + return nullptr; + } + + jobject value = env->NewObject(activeChangedStructClass, activeChangedStructCtor, value_promisedActiveDuration); + + return value; + } default: *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; break; diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 1f3b1305b5f52f..c9f559f9f61915 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -3246,6 +3246,12 @@ class ChipClusters: "clusterName": "BridgedDeviceBasicInformation", "clusterId": 0x00000039, "commands": { + 0x00000080: { + "commandId": 0x00000080, + "commandName": "KeepActive", + "args": { + }, + }, }, "attributes": { 0x00000001: { diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index bf94c7ea84ea08..13c6fe3d9f4dab 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -11425,6 +11425,10 @@ class ProductFinishEnum(MatterIntEnum): # enum value. This specific should never be transmitted. kUnknownEnumValue = 6, + class Bitmaps: + class Feature(IntFlag): + kBridgedICDSupport = 0x100000 + class Structs: @dataclass class ProductAppearanceStruct(ClusterObject): @@ -11439,6 +11443,20 @@ def descriptor(cls) -> ClusterObjectDescriptor: finish: 'BridgedDeviceBasicInformation.Enums.ProductFinishEnum' = 0 primaryColor: 'typing.Union[Nullable, BridgedDeviceBasicInformation.Enums.ColorEnum]' = NullValue + class Commands: + @dataclass + class KeepActive(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000039 + command_id: typing.ClassVar[int] = 0x00000080 + is_client: typing.ClassVar[bool] = True + response_type: typing.ClassVar[str] = None + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ]) + class Attributes: @dataclass class VendorName(ClusterAttributeDescriptor): @@ -11863,6 +11881,25 @@ def descriptor(cls) -> ClusterObjectDescriptor: reachableNewValue: 'bool' = False + @dataclass + class ActiveChanged(ClusterEvent): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000039 + + @ChipUtility.classproperty + def event_id(cls) -> int: + return 0x00000080 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="promisedActiveDuration", Tag=0, Type=uint), + ]) + + promisedActiveDuration: 'uint' = 0 + @dataclass class Switch(Cluster): diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index c1ad2950a339f2..7c3e36f0797323 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -3670,6 +3670,15 @@ MTR_PROVISIONALLY_AVAILABLE MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) @interface MTRBaseClusterBridgedDeviceBasicInformation : MTRGenericBaseCluster +/** + * Command KeepActive + * + * The server SHALL attempt to keep the devices specified active for StayActiveDuration milliseconds when they are next active. + */ +- (void)keepActiveWithParams:(MTRBridgedDeviceBasicInformationClusterKeepActiveParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)keepActiveWithCompletion:(MTRStatusCompletion)completion + MTR_PROVISIONALLY_AVAILABLE; + - (void)readAttributeVendorNameWithCompletion:(void (^)(NSString * _Nullable value, NSError * _Nullable error))completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)subscribeAttributeVendorNameWithParams:(MTRSubscribeParams *)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished @@ -17994,6 +18003,10 @@ typedef NS_ENUM(uint8_t, MTRBridgedDeviceBasicInformationProductFinish) { MTRBridgedDeviceBasicInformationProductFinishFabric MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x05, } MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)); +typedef NS_OPTIONS(uint32_t, MTRBridgedDeviceBasicInformationFeature) { + MTRBridgedDeviceBasicInformationFeatureBridgedICDSupport MTR_PROVISIONALLY_AVAILABLE = 0x100000, +} MTR_PROVISIONALLY_AVAILABLE; + typedef NS_OPTIONS(uint32_t, MTRSwitchFeature) { MTRSwitchFeatureLatchingSwitch MTR_AVAILABLE(ios(16.2), macos(13.1), watchos(9.2), tvos(16.2)) = 0x1, MTRSwitchFeatureMomentarySwitch MTR_AVAILABLE(ios(16.2), macos(13.1), watchos(9.2), tvos(16.2)) = 0x2, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index b4f9ee8e82e653..ddb25fb19bd0a8 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -30658,6 +30658,35 @@ + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheC @implementation MTRBaseClusterBridgedDeviceBasicInformation +- (void)keepActiveWithCompletion:(MTRStatusCompletion)completion +{ + [self keepActiveWithParams:nil completion:completion]; +} +- (void)keepActiveWithParams:(MTRBridgedDeviceBasicInformationClusterKeepActiveParams * _Nullable)params completion:(MTRStatusCompletion)completion +{ + if (params == nil) { + params = [[MTRBridgedDeviceBasicInformationClusterKeepActiveParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = BridgedDeviceBasicInformation::Commands::KeepActive::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.callbackQueue + completion:responseHandler]; +} + - (void)readAttributeVendorNameWithCompletion:(void (^)(NSString * _Nullable value, NSError * _Nullable error))completion { using TypeInfo = BridgedDeviceBasicInformation::Attributes::VendorName::TypeInfo; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index 094d58964241fa..ff6351d9a50ff3 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -6158,6 +6158,11 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { MTRCommandIDTypeClusterTimeSynchronizationCommandSetDSTOffsetID MTR_PROVISIONALLY_AVAILABLE = 0x00000004, MTRCommandIDTypeClusterTimeSynchronizationCommandSetDefaultNTPID MTR_PROVISIONALLY_AVAILABLE = 0x00000005, + // Cluster BridgedDeviceBasic deprecated command id names + + // Cluster BridgedDeviceBasicInformation commands + MTRCommandIDTypeClusterBridgedDeviceBasicInformationCommandKeepActiveID MTR_PROVISIONALLY_AVAILABLE = 0x00000080, + // Cluster AdministratorCommissioning deprecated command id names MTRClusterAdministratorCommissioningCommandOpenCommissioningWindowID MTR_DEPRECATED("Please use MTRCommandIDTypeClusterAdministratorCommissioningCommandOpenCommissioningWindowID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) @@ -7246,6 +7251,7 @@ typedef NS_ENUM(uint32_t, MTREventIDType) { MTREventIDTypeClusterBridgedDeviceBasicInformationEventShutDownID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000001, MTREventIDTypeClusterBridgedDeviceBasicInformationEventLeaveID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000002, MTREventIDTypeClusterBridgedDeviceBasicInformationEventReachableChangedID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000003, + MTREventIDTypeClusterBridgedDeviceBasicInformationEventActiveChangedID MTR_PROVISIONALLY_AVAILABLE = 0x00000080, // Cluster Switch deprecated event names MTRClusterSwitchEventSwitchLatchedID diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 7c4d66189c3b4d..a30b71bc75cb22 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -1699,6 +1699,10 @@ MTR_PROVISIONALLY_AVAILABLE MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) @interface MTRClusterBridgedDeviceBasicInformation : MTRGenericCluster +- (void)keepActiveWithParams:(MTRBridgedDeviceBasicInformationClusterKeepActiveParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)keepActiveWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion + MTR_PROVISIONALLY_AVAILABLE; + - (NSDictionary * _Nullable)readAttributeVendorNameWithParams:(MTRReadParams * _Nullable)params MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (NSDictionary * _Nullable)readAttributeVendorIDWithParams:(MTRReadParams * _Nullable)params MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); @@ -1753,8 +1757,8 @@ MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) @interface MTRClusterBridgedDeviceBasicInformation (Availability) /** - * The queue is currently unused, but may be used in the future for calling completions - * for command invocations if commands are added to this cluster. + * For all instance methods that take a completion (i.e. command invocations), + * the completion will be called on the provided queue. */ - (instancetype _Nullable)initWithDevice:(MTRDevice *)device endpointID:(NSNumber *)endpointID diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index b638b2c8f56890..bab799b843c24f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -4944,6 +4944,37 @@ - (void)setDefaultNTPWithParams:(MTRTimeSynchronizationClusterSetDefaultNTPParam @implementation MTRClusterBridgedDeviceBasicInformation +- (void)keepActiveWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(MTRStatusCompletion)completion +{ + [self keepActiveWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; +} +- (void)keepActiveWithParams:(MTRBridgedDeviceBasicInformationClusterKeepActiveParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion +{ + if (params == nil) { + params = [[MTRBridgedDeviceBasicInformationClusterKeepActiveParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = BridgedDeviceBasicInformation::Commands::KeepActive::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + expectedValues:expectedValues + expectedValueInterval:expectedValueIntervalMs + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.callbackQueue + completion:responseHandler]; +} + - (NSDictionary * _Nullable)readAttributeVendorNameWithParams:(MTRReadParams * _Nullable)params { return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeBridgedDeviceBasicInformationID) attributeID:@(MTRAttributeIDTypeClusterBridgedDeviceBasicInformationAttributeVendorNameID) params:params]; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 5981d8292c039c..3746227a4f9d21 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -2915,6 +2915,34 @@ MTR_PROVISIONALLY_AVAILABLE @property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRBridgedDeviceBasicInformationClusterKeepActiveParams : NSObject +/** + * Controls whether the command is a timed command (using Timed Invoke). + * + * If nil (the default value), a regular invoke is done for commands that do + * not require a timed invoke and a timed invoke with some default timed request + * timeout is done for commands that require a timed invoke. + * + * If not nil, a timed invoke is done, with the provided value used as the timed + * request timeout. The value should be chosen small enough to provide the + * desired security properties but large enough that it will allow a round-trip + * from the sever to the client (for the status response and actual invoke + * request) within the timeout window. + * + */ +@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; + +/** + * Controls how much time, in seconds, we will allow for the server to process the command. + * + * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * + * If nil, the framework will try to select an appropriate timeout value itself. + */ +@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +@end + MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRAdministratorCommissioningClusterOpenCommissioningWindowParams : NSObject diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 295f8444db0b63..8d18518670e808 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -7556,6 +7556,79 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end +@implementation MTRBridgedDeviceBasicInformationClusterKeepActiveParams +- (instancetype)init +{ + if (self = [super init]) { + _timedInvokeTimeoutMs = nil; + _serverSideProcessingTimeout = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRBridgedDeviceBasicInformationClusterKeepActiveParams alloc] init]; + + other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; + other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])]; + return descriptionString; +} + +@end + +@implementation MTRBridgedDeviceBasicInformationClusterKeepActiveParams (InternalMethods) + +- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +{ + chip::app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Type encodableStruct; + ListFreer listFreer; + + auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); + if (buffer.IsNull()) { + return CHIP_ERROR_NO_MEMORY; + } + + chip::System::PacketBufferTLVWriter writer; + // Commands never need chained buffers, since they cannot be chunked. + writer.Init(std::move(buffer), /* useChainedBuffers = */ false); + + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); + + ReturnErrorOnFailure(writer.Finalize(&buffer)); + + reader.Init(std::move(buffer)); + return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); +} + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error +{ + chip::System::PacketBufferTLVReader reader; + CHIP_ERROR err = [self _encodeToTLVReader:reader]; + if (err != CHIP_NO_ERROR) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:err]; + } + return nil; + } + + auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); + if (decodedObj == nil) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + } + } + return decodedObj; +} +@end + @implementation MTRAdministratorCommissioningClusterOpenCommissioningWindowParams - (instancetype)init { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h index d3746f9d936895..67c37229a00dcc 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h @@ -496,6 +496,12 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface MTRBridgedDeviceBasicInformationClusterKeepActiveParams (InternalMethods) + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; + +@end + @interface MTRAdministratorCommissioningClusterOpenCommissioningWindowParams (InternalMethods) - (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm index e2fc7e70cba67b..13f125b6328642 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm @@ -1382,6 +1382,23 @@ static id _Nullable DecodeEventPayloadForBridgedDeviceBasicInformationCluster(Ev return value; } + case Events::ActiveChanged::Id: { + Events::ActiveChanged::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + + __auto_type * value = [MTRBridgedDeviceBasicInformationClusterActiveChangedEvent new]; + + do { + NSNumber * _Nonnull memberValue; + memberValue = [NSNumber numberWithUnsignedInt:cppValue.promisedActiveDuration]; + value.promisedActiveDuration = memberValue; + } while (0); + + return value; + } default: { break; } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index b804aee8b5ace1..d4da2052d3cb3e 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -649,6 +649,11 @@ MTR_DEPRECATED("Please use MTRBridgedDeviceBasicInformationClusterReachableChang @property (nonatomic, copy) NSNumber * _Nonnull reachableNewValue MTR_DEPRECATED("Please use MTRBridgedDeviceBasicInformationClusterReachableChangedEvent", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)); @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRBridgedDeviceBasicInformationClusterActiveChangedEvent : NSObject +@property (nonatomic, copy) NSNumber * _Nonnull promisedActiveDuration MTR_PROVISIONALLY_AVAILABLE; +@end + MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRSwitchClusterSwitchLatchedEvent : NSObject @property (nonatomic, copy, getter=getNewPosition) NSNumber * _Nonnull newPosition MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index d3182118beb89c..99503c79d6e2bf 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -2246,6 +2246,33 @@ @implementation MTRBridgedDeviceBasicClusterReachableChangedEvent : MTRBridgedDe @dynamic reachableNewValue; @end +@implementation MTRBridgedDeviceBasicInformationClusterActiveChangedEvent +- (instancetype)init +{ + if (self = [super init]) { + + _promisedActiveDuration = @(0); + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTRBridgedDeviceBasicInformationClusterActiveChangedEvent alloc] init]; + + other.promisedActiveDuration = self.promisedActiveDuration; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: promisedActiveDuration:%@; >", NSStringFromClass([self class]), _promisedActiveDuration]; + return descriptionString; +} + +@end + @implementation MTRSwitchClusterSwitchLatchedEvent - (instancetype)init { diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 80e42e929fe08a..bb2d5a3f3dd501 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -5826,6 +5826,12 @@ bool emberAfTimeSynchronizationClusterSetDSTOffsetCallback( bool emberAfTimeSynchronizationClusterSetDefaultNTPCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::TimeSynchronization::Commands::SetDefaultNTP::DecodableType & commandData); +/** + * @brief Bridged Device Basic Information Cluster KeepActive Command callback (from client) + */ +bool emberAfBridgedDeviceBasicInformationClusterKeepActiveCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::DecodableType & commandData); /** * @brief Administrator Commissioning Cluster OpenCommissioningWindow Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index 62bf3473649525..fd0f8d24d26dc6 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -1480,6 +1480,12 @@ enum class ProductFinishEnum : uint8_t // enum value. This specific should never be transmitted. kUnknownEnumValue = 6, }; + +// Bitmap for Feature +enum class Feature : uint32_t +{ + kBridgedICDSupport = 0x100000, +}; } // namespace BridgedDeviceBasicInformation namespace Switch { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 8fc3c32562d3d7..7a08cb455c6452 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -7678,7 +7678,28 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } // namespace ProductAppearanceStruct } // namespace Structs -namespace Commands {} // namespace Commands +namespace Commands { +namespace KeepActive { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + } +} +} // namespace KeepActive. +} // namespace Commands namespace Attributes { CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path) @@ -7848,6 +7869,41 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } } } // namespace ReachableChanged. +namespace ActiveChanged { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + TLV::TLVType outer; + ReturnErrorOnFailure(aWriter.StartContainer(aTag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kPromisedActiveDuration), promisedActiveDuration)); + return aWriter.EndContainer(outer); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kPromisedActiveDuration)) + { + err = DataModel::Decode(reader, promisedActiveDuration); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace ActiveChanged. } // namespace Events } // namespace BridgedDeviceBasicInformation @@ -31605,6 +31661,13 @@ bool CommandIsFabricScoped(ClusterId aCluster, CommandId aCommand) return false; } } + case Clusters::BridgedDeviceBasicInformation::Id: { + switch (aCommand) + { + default: + return false; + } + } case Clusters::AdministratorCommissioning::Id: { switch (aCommand) { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 9c335d4ba91dcb..5952309732b90c 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -10566,6 +10566,47 @@ using DecodableType = Type; } // namespace ProductAppearanceStruct } // namespace Structs +namespace Commands { +// Forward-declarations so we can reference these later. + +namespace KeepActive { +struct Type; +struct DecodableType; +} // namespace KeepActive + +} // namespace Commands + +namespace Commands { +namespace KeepActive { +enum class Fields : uint8_t +{ +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::KeepActive::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BridgedDeviceBasicInformation::Id; } + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = DataModel::NullObjectType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::KeepActive::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BridgedDeviceBasicInformation::Id; } + + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace KeepActive +} // namespace Commands + namespace Attributes { namespace VendorName { @@ -10965,6 +11006,39 @@ struct DecodableType CHIP_ERROR Decode(TLV::TLVReader & reader); }; } // namespace ReachableChanged +namespace ActiveChanged { +static constexpr PriorityLevel kPriorityLevel = PriorityLevel::Info; + +enum class Fields : uint8_t +{ + kPromisedActiveDuration = 0, +}; + +struct Type +{ +public: + static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } + static constexpr EventId GetEventId() { return Events::ActiveChanged::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BridgedDeviceBasicInformation::Id; } + static constexpr bool kIsFabricScoped = false; + + uint32_t promisedActiveDuration = static_cast(0); + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; +}; + +struct DecodableType +{ +public: + static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } + static constexpr EventId GetEventId() { return Events::ActiveChanged::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BridgedDeviceBasicInformation::Id; } + + uint32_t promisedActiveDuration = static_cast(0); + + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +} // namespace ActiveChanged } // namespace Events } // namespace BridgedDeviceBasicInformation namespace Switch { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index 4a8e4a830a44f7..926df4190a620e 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -449,6 +449,16 @@ static constexpr CommandId Id = 0x00000005; } // namespace Commands } // namespace TimeSynchronization +namespace BridgedDeviceBasicInformation { +namespace Commands { + +namespace KeepActive { +static constexpr CommandId Id = 0x00000080; +} // namespace KeepActive + +} // namespace Commands +} // namespace BridgedDeviceBasicInformation + namespace AdministratorCommissioning { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h index 6e6191fe45c21c..3a997b42d51bb5 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h @@ -220,6 +220,10 @@ namespace ReachableChanged { static constexpr EventId Id = 0x00000003; } // namespace ReachableChanged +namespace ActiveChanged { +static constexpr EventId Id = 0x00000080; +} // namespace ActiveChanged + } // namespace Events } // namespace BridgedDeviceBasicInformation diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index dd2f2c40082af8..99221c08e3f71c 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -3392,6 +3392,7 @@ class TimeSynchronizationSetDefaultNTP : public ClusterCommand | Cluster BridgedDeviceBasicInformation | 0x0039 | |------------------------------------------------------------------------------| | Commands: | | +| * KeepActive | 0x80 | |------------------------------------------------------------------------------| | Attributes: | | | * VendorName | 0x0001 | @@ -3422,8 +3423,46 @@ class TimeSynchronizationSetDefaultNTP : public ClusterCommand | * ShutDown | 0x0001 | | * Leave | 0x0002 | | * ReachableChanged | 0x0003 | +| * ActiveChanged | 0x0080 | \*----------------------------------------------------------------------------*/ +/* + * Command KeepActive + */ +class BridgedDeviceBasicInformationKeepActive : public ClusterCommand +{ +public: + BridgedDeviceBasicInformationKeepActive(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("keep-active", credsIssuerConfig) + { + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BridgedDeviceBasicInformation::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, + commandId, endpointIds.at(0)); + return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); + } + + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BridgedDeviceBasicInformation::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, + groupId); + + return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); + } + +private: + chip::app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Type mRequest; +}; + /*----------------------------------------------------------------------------*\ | Cluster Switch | 0x003B | |------------------------------------------------------------------------------| @@ -18116,7 +18155,8 @@ void registerClusterBridgedDeviceBasicInformation(Commands & commands, Credentia // // Commands // - make_unique(Id, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // // // Attributes // @@ -18221,11 +18261,13 @@ void registerClusterBridgedDeviceBasicInformation(Commands & commands, Credentia make_unique(Id, "shut-down", Events::ShutDown::Id, credsIssuerConfig), // make_unique(Id, "leave", Events::Leave::Id, credsIssuerConfig), // make_unique(Id, "reachable-changed", Events::ReachableChanged::Id, credsIssuerConfig), // + make_unique(Id, "active-changed", Events::ActiveChanged::Id, credsIssuerConfig), // make_unique(Id, credsIssuerConfig), // make_unique(Id, "start-up", Events::StartUp::Id, credsIssuerConfig), // make_unique(Id, "shut-down", Events::ShutDown::Id, credsIssuerConfig), // make_unique(Id, "leave", Events::Leave::Id, credsIssuerConfig), // make_unique(Id, "reachable-changed", Events::ReachableChanged::Id, credsIssuerConfig), // + make_unique(Id, "active-changed", Events::ActiveChanged::Id, credsIssuerConfig), // }; commands.RegisterCluster(clusterName, clusterCommands); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index d062e7aeac77c5..5071a49a141e51 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -5883,6 +5883,22 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const BridgedDeviceBasicInformation::Events::ActiveChanged::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = DataModelLogger::LogValue("PromisedActiveDuration", indent + 1, value.promisedActiveDuration); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'PromisedActiveDuration'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const Switch::Events::SwitchLatched::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); @@ -19824,6 +19840,11 @@ CHIP_ERROR DataModelLogger::LogEvent(const chip::app::EventHeader & header, chip ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("ReachableChanged", 1, value); } + case BridgedDeviceBasicInformation::Events::ActiveChanged::Id: { + chip::app::Clusters::BridgedDeviceBasicInformation::Events::ActiveChanged::DecodableType value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("ActiveChanged", 1, value); + } } break; } diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index 8a74b57e503b30..95cc96d293b574 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -469,6 +469,8 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::BridgedDeviceBasicInformation::Events::ReachableChanged::DecodableType & value); +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::BridgedDeviceBasicInformation::Events::ActiveChanged::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::Switch::Events::SwitchLatched::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 39f9c949872dfe..17451309d1e621 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -39469,6 +39469,7 @@ class SubscribeAttributeTimeSynchronizationClusterRevision : public SubscribeAtt | Cluster BridgedDeviceBasicInformation | 0x0039 | |------------------------------------------------------------------------------| | Commands: | | +| * KeepActive | 0x80 | |------------------------------------------------------------------------------| | Attributes: | | | * VendorName | 0x0001 | @@ -39499,8 +39500,56 @@ class SubscribeAttributeTimeSynchronizationClusterRevision : public SubscribeAtt | * ShutDown | 0x0001 | | * Leave | 0x0002 | | * ReachableChanged | 0x0003 | +| * ActiveChanged | 0x0080 | \*----------------------------------------------------------------------------*/ +#if MTR_ENABLE_PROVISIONAL +/* + * Command KeepActive + */ +class BridgedDeviceBasicInformationKeepActive : public ClusterCommand { +public: + BridgedDeviceBasicInformationKeepActive() + : ClusterCommand("keep-active") + { + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BridgedDeviceBasicInformation::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBridgedDeviceBasicInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRBridgedDeviceBasicInformationClusterKeepActiveParams alloc] init]; + params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; + uint16_t repeatCount = mRepeatCount.ValueOr(1); + uint16_t __block responsesNeeded = repeatCount; + while (repeatCount--) { + [cluster keepActiveWithParams:params completion: + ^(NSError * _Nullable error) { + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; + } + return CHIP_NO_ERROR; + } + +private: +}; + +#endif // MTR_ENABLE_PROVISIONAL + /* * Attribute VendorName */ @@ -190895,6 +190944,9 @@ void registerClusterBridgedDeviceBasicInformation(Commands & commands) commands_list clusterCommands = { make_unique(Id), // +#if MTR_ENABLE_PROVISIONAL + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL make_unique(Id), // make_unique(Id), // make_unique(Id), // From c097d826b9b3ca8a52026c2126f2e87bfe7eb924 Mon Sep 17 00:00:00 2001 From: Andy Salisbury Date: Thu, 25 Jul 2024 19:35:58 -0400 Subject: [PATCH 09/17] Add the missing implementation for BdxTransferSession::RejectTransfer. (#34484) * Add the missing implementation for BdxTransferSession::RejectTransfer. * Style fix. --------- Co-authored-by: Andrei Litvin --- src/protocols/bdx/BdxTransferSession.cpp | 11 ++++ .../bdx/tests/TestBdxTransferSession.cpp | 61 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/protocols/bdx/BdxTransferSession.cpp b/src/protocols/bdx/BdxTransferSession.cpp index f6c54985ab5cd1..99588f0770a72e 100644 --- a/src/protocols/bdx/BdxTransferSession.cpp +++ b/src/protocols/bdx/BdxTransferSession.cpp @@ -261,6 +261,17 @@ CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData return CHIP_NO_ERROR; } +CHIP_ERROR TransferSession::RejectTransfer(StatusCode reason) +{ + VerifyOrReturnError(mState == TransferState::kNegotiateTransferParams, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE); + + PrepareStatusReport(reason); + mState = TransferState::kTransferDone; + + return CHIP_NO_ERROR; +} + CHIP_ERROR TransferSession::PrepareBlockQuery() { const MessageType msgType = MessageType::BlockQuery; diff --git a/src/protocols/bdx/tests/TestBdxTransferSession.cpp b/src/protocols/bdx/tests/TestBdxTransferSession.cpp index 8fcc4fab312f26..9a383752551064 100644 --- a/src/protocols/bdx/tests/TestBdxTransferSession.cpp +++ b/src/protocols/bdx/tests/TestBdxTransferSession.cpp @@ -124,6 +124,13 @@ void VerifyNoMoreOutput(TransferSession & transferSession) EXPECT_EQ(event.EventType, TransferSession::OutputEventType::kNone); } +void VerifyInternalError(TransferSession & transferSession) +{ + TransferSession::OutputEvent event; + transferSession.PollOutput(event, kNoAdvanceTime); + EXPECT_EQ(event.EventType, TransferSession::OutputEventType::kInternalError); +} + // Helper method for initializing two TransferSession objects, generating a TransferInit message, and passing it to a responding // TransferSession. void SendAndVerifyTransferInit(TransferSession::OutputEvent & outEvent, System::Clock::Timeout timeout, TransferSession & initiator, @@ -235,6 +242,30 @@ void SendAndVerifyAcceptMsg(TransferSession::OutputEvent & outEvent, TransferSes EXPECT_LE(acceptReceiver.GetTransferBlockSize(), initData.MaxBlockSize); } +void SendAndVerifyRejectMsg(TransferSession::OutputEvent & outEvent, TransferSession & rejectSender, StatusCode reason, + TransferSession & rejectReceiver) +{ + CHIP_ERROR err = rejectSender.RejectTransfer(reason); + EXPECT_EQ(err, CHIP_NO_ERROR); + + // Verify Sender emits status message for sending + rejectSender.PollOutput(outEvent, kNoAdvanceTime); + VerifyNoMoreOutput(rejectSender); + EXPECT_EQ(outEvent.EventType, TransferSession::OutputEventType::kMsgToSend); + System::PacketBufferHandle statusReportMsg = outEvent.MsgData.Retain(); + VerifyStatusReport(std::move(outEvent.MsgData), reason); + + // Pass status message to rejectReceiver + err = AttachHeaderAndSend(outEvent.msgTypeData, std::move(outEvent.MsgData), rejectReceiver); + EXPECT_EQ(err, CHIP_NO_ERROR); + + // Verify received status message. + rejectReceiver.PollOutput(outEvent, kNoAdvanceTime); + VerifyInternalError(rejectReceiver); + EXPECT_EQ(outEvent.EventType, TransferSession::OutputEventType::kStatusReceived); + EXPECT_EQ(outEvent.statusData.statusCode, reason); +} + // Helper method for preparing a sending a BlockQuery message between two TransferSession objects. void SendAndVerifyQuery(TransferSession & queryReceiver, TransferSession & querySender, TransferSession::OutputEvent & outEvent) { @@ -698,3 +729,33 @@ TEST_F(TestBdxTransferSession, TestDuplicateBlockError) EXPECT_EQ(outEvent.statusData.statusCode, StatusCode::kBadBlockCounter); } } + +TEST_F(TestBdxTransferSession, TestRejectTransfer) +{ + TransferSession::OutputEvent outEvent; + TransferSession initiatingReceiver; + TransferSession respondingSender; + + // Chosen arbitrarily for this test + uint16_t proposedBlockSize = 128; + System::Clock::Timeout timeout = System::Clock::Seconds16(24); + TransferControlFlags driveMode = TransferControlFlags::kReceiverDrive; + + // ReceiveInit parameters + TransferSession::TransferInitData initOptions; + initOptions.TransferCtlFlags = driveMode; + initOptions.MaxBlockSize = proposedBlockSize; + char testFileDes[9] = { "test.txt" }; + initOptions.FileDesLength = static_cast(strlen(testFileDes)); + initOptions.FileDesignator = reinterpret_cast(testFileDes); + + // Initialize respondingSender and pass ReceiveInit message + BitFlags senderOpts; + senderOpts.Set(driveMode); + + SendAndVerifyTransferInit(outEvent, timeout, initiatingReceiver, TransferRole::kReceiver, initOptions, respondingSender, + senderOpts, proposedBlockSize); + + // Reject the transfer with a status + SendAndVerifyRejectMsg(outEvent, respondingSender, StatusCode::kResponderBusy, initiatingReceiver); +} From 68ef6f11eb1c7f2c0a0b0b5d00795eb95c4f1dcf Mon Sep 17 00:00:00 2001 From: Alex Tsitsiura Date: Fri, 26 Jul 2024 03:22:43 +0300 Subject: [PATCH 10/17] [Telink] Readme files update & Add USB target to CI (#34502) * [Telink] Add USB target to CI * [Telink] update readme files * [Telink] fix the unit test --- .github/workflows/examples-telink.yaml | 8 ++-- .../air-quality-sensor-app/telink/README.md | 36 ++++++++++----- examples/all-clusters-app/telink/README.md | 36 ++++++++++----- .../all-clusters-minimal-app/telink/README.md | 44 +++++++++++++------ examples/bridge-app/telink/README.md | 36 ++++++++++----- examples/contact-sensor-app/telink/README.md | 36 ++++++++++----- examples/light-switch-app/telink/README.md | 36 ++++++++++----- examples/lighting-app/telink/README.md | 40 ++++++++++++----- examples/lock-app/telink/README.md | 36 ++++++++++----- examples/ota-requestor-app/telink/README.md | 44 +++++++++++++------ examples/pump-app/telink/README.md | 36 ++++++++++----- examples/pump-controller-app/telink/README.md | 36 ++++++++++----- examples/shell/telink/README.md | 24 ++++++++-- examples/smoke-co-alarm-app/telink/README.md | 36 ++++++++++----- .../telink/README.md | 36 ++++++++++----- examples/thermostat/telink/README.md | 36 ++++++++++----- examples/window-app/telink/README.md | 40 ++++++++++++----- scripts/build/build/targets.py | 1 + scripts/build/builders/telink.py | 7 ++- .../build/testdata/all_targets_linux_x64.txt | 2 +- 20 files changed, 436 insertions(+), 170 deletions(-) diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml index 045972682ad04a..b26453fa1bbb9d 100644 --- a/.github/workflows/examples-telink.yaml +++ b/.github/workflows/examples-telink.yaml @@ -189,13 +189,13 @@ jobs: - name: clean out build output run: rm -rf ./out - - name: Build example Telink (B91) Pump App + - name: Build example Telink (B91 USB) Pump App run: | ./scripts/run_in_build_env.sh \ - "./scripts/build/build_examples.py --target 'telink-tlsr9518adk80d-pump' build" + "./scripts/build/build_examples.py --target 'telink-tlsr9518adk80d-pump-usb' build" .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ - telink tlsr9518adk80d pump-app \ - out/telink-tlsr9518adk80d-pump/zephyr/zephyr.elf \ + telink tlsr9518adk80d pump-app-usb \ + out/telink-tlsr9518adk80d-pump-usb/zephyr/zephyr.elf \ /tmp/bloat_reports/ - name: clean out build output diff --git a/examples/air-quality-sensor-app/telink/README.md b/examples/air-quality-sensor-app/telink/README.md index 64b394c046b51a..e2c4b49a699991 100644 --- a/examples/air-quality-sensor-app/telink/README.md +++ b/examples/air-quality-sensor-app/telink/README.md @@ -4,6 +4,17 @@ You can use this example as a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -12,7 +23,7 @@ You can use this example as a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -24,8 +35,8 @@ You can use this example as a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -35,9 +46,12 @@ You can use this example as a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -56,16 +70,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | `AirQuality` control | Manually triggers the `AirQuality` state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | `AirQuality` control | Manually triggers the `AirQuality` state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/all-clusters-app/telink/README.md b/examples/all-clusters-app/telink/README.md index 89d8221af75d3f..8404672d3134e6 100644 --- a/examples/all-clusters-app/telink/README.md +++ b/examples/all-clusters-app/telink/README.md @@ -6,6 +6,17 @@ creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -14,7 +25,7 @@ creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -26,8 +37,8 @@ creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -37,9 +48,12 @@ creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -58,16 +72,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Not used | Not used | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Not used | Not used | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/all-clusters-minimal-app/telink/README.md b/examples/all-clusters-minimal-app/telink/README.md index 396afb1cc63091..f3a0646df97743 100644 --- a/examples/all-clusters-minimal-app/telink/README.md +++ b/examples/all-clusters-minimal-app/telink/README.md @@ -6,6 +6,17 @@ for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -14,7 +25,7 @@ for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -26,8 +37,8 @@ for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -37,9 +48,12 @@ for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -58,27 +72,31 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Not used | Not used | -| Button 2 | Not used | Not used | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Not used | Not used | +| Button 2 | Not used | Not used | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs -**Red** LED indicates current state of Thread network. It ables to be in +#### Indicate current state of Thread network + +**Red** LED indicates current state of Thread network. It is able to be in following states: | State | Description | | :-------------------------- | :--------------------------------------------------------------------------- | | Blinks with short pulses | Device is not commissioned to Thread, Thread is disabled | -| Blinls with frequent pulses | Device is commissioned, Thread enabled. Device trying to JOIN thread network | -| Blinks with whde pulses | Device commissioned and joined to thread network as CHILD | +| Blinks with frequent pulses | Device is commissioned, Thread enabled. Device trying to JOIN thread network | +| Blinks with wide pulses | Device commissioned and joined to thread network as CHILD | ### CHIP tool commands diff --git a/examples/bridge-app/telink/README.md b/examples/bridge-app/telink/README.md index 0855689cd1201f..7dc29dff9d1d58 100644 --- a/examples/bridge-app/telink/README.md +++ b/examples/bridge-app/telink/README.md @@ -83,6 +83,17 @@ defined: - This macro is used to declare an endpoint and its associated cluster list, which must be previously defined by the `DECLARE_DYNAMIC_CLUSTER...` macros. +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -91,7 +102,7 @@ defined: $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -103,8 +114,8 @@ defined: $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -114,9 +125,12 @@ defined: MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -135,16 +149,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Lighting control | Manually triggers the lighting state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Lighting control | Manually triggers the lighting state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/contact-sensor-app/telink/README.md b/examples/contact-sensor-app/telink/README.md index 964b05a76ba109..cbceff71361ccf 100755 --- a/examples/contact-sensor-app/telink/README.md +++ b/examples/contact-sensor-app/telink/README.md @@ -4,6 +4,17 @@ You can use this example as a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -12,7 +23,7 @@ You can use this example as a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -24,8 +35,8 @@ You can use this example as a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -35,9 +46,12 @@ You can use this example as a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -56,16 +70,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Toggle Contact State | Manually triggers the Contact Sensor State | -| Button 3 | NA | NA | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Toggle Contact State | Manually triggers the Contact Sensor State | +| Button 3 | NA | NA | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/light-switch-app/telink/README.md b/examples/light-switch-app/telink/README.md index d222116f5f1a7f..c60dd6a27c3584 100755 --- a/examples/light-switch-app/telink/README.md +++ b/examples/light-switch-app/telink/README.md @@ -9,6 +9,17 @@ creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -17,7 +28,7 @@ creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -29,8 +40,8 @@ creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -40,9 +51,12 @@ creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -61,16 +75,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Light Switch control | Manually triggers the light switch state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Light Switch control | Manually triggers the light switch state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/lighting-app/telink/README.md b/examples/lighting-app/telink/README.md index 6c2269007e8ac3..0bf52ea12c28fd 100644 --- a/examples/lighting-app/telink/README.md +++ b/examples/lighting-app/telink/README.md @@ -7,6 +7,17 @@ a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -15,7 +26,7 @@ a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -27,8 +38,8 @@ a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -38,9 +49,12 @@ a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -59,16 +73,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Lighting control | Manually triggers the lighting state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Lighting control | Manually triggers the lighting state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs @@ -249,9 +265,9 @@ application of OTA image. The RPCs in `lighting-common/lighting_service/lighting_service.proto` can be used to control various functionalities of the lighting app from a USB-connected host computer. To build the example with the RPC server, run the following -command with _build-target_ replaced with the build target name of the Telink +command with __ replaced with the build target name of the Telink Semiconductor's kit you own: ``` - $ west build -b tlsr9518adk80d -- -DOVERLAY_CONFIG=rpc.overlay + $ west build -b -- -DOVERLAY_CONFIG=rpc.overlay ``` diff --git a/examples/lock-app/telink/README.md b/examples/lock-app/telink/README.md index 8386a524c48d41..8e0d605fd85dc6 100755 --- a/examples/lock-app/telink/README.md +++ b/examples/lock-app/telink/README.md @@ -7,6 +7,17 @@ a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -15,7 +26,7 @@ a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -27,8 +38,8 @@ a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -38,9 +49,12 @@ a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -59,16 +73,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Lock control | Manually triggers the bolt lock state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Lock control | Manually triggers the bolt lock state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/ota-requestor-app/telink/README.md b/examples/ota-requestor-app/telink/README.md index c549804e42f627..d8590c6a0cc4d7 100755 --- a/examples/ota-requestor-app/telink/README.md +++ b/examples/ota-requestor-app/telink/README.md @@ -1,5 +1,16 @@ ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -8,7 +19,7 @@ $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -20,8 +31,8 @@ $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -31,9 +42,12 @@ MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -52,16 +66,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | NA | NA | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | NA | NA | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs @@ -99,12 +115,14 @@ be used to specify the the effect. It is able to be in following effects: 2. Pair with device ``` - ${CHIP_TOOL_DIR}/chip-tool pairing code ${NODE_ID_TO_ASSIGN} MT:D8XA0CQM00KA0648G00 + ${CHIP_TOOL_DIR}/chip-tool pairing ble-thread ${NODE_ID} hex:${DATASET} ${PIN_CODE} ${DISCRIMINATOR} ``` - here: + Example: - - \${NODE_ID_TO_ASSIGN} is the node id to assign to the ota requestor + ``` + ./chip-tool pairing ble-thread 1234 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd61f77bd3df233e051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f010212340410445f2b5ca6f2a93a55ce570a70efeecb0c0402a0fff8 20202021 3840 + ``` ### OTA with Linux OTA Provider diff --git a/examples/pump-app/telink/README.md b/examples/pump-app/telink/README.md index 885cf7230856bc..2a89b7514b1c98 100755 --- a/examples/pump-app/telink/README.md +++ b/examples/pump-app/telink/README.md @@ -8,6 +8,17 @@ reference for creating your own pump application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -16,7 +27,7 @@ reference for creating your own pump application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -28,8 +39,8 @@ reference for creating your own pump application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -39,9 +50,12 @@ reference for creating your own pump application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -60,16 +74,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Lock control | Manually triggers the bolt lock state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Lock control | Manually triggers the bolt lock state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/pump-controller-app/telink/README.md b/examples/pump-controller-app/telink/README.md index a49b0999ddebac..529cc37e002bf5 100755 --- a/examples/pump-controller-app/telink/README.md +++ b/examples/pump-controller-app/telink/README.md @@ -9,6 +9,17 @@ your own pump application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -17,7 +28,7 @@ your own pump application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -29,8 +40,8 @@ your own pump application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -40,9 +51,12 @@ your own pump application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -61,16 +75,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Lock control | Manually triggers the bolt lock state | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Lock control | Manually triggers the bolt lock state | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/shell/telink/README.md b/examples/shell/telink/README.md index 0d445a3838ec3a..14e8bedb1c3bf0 100755 --- a/examples/shell/telink/README.md +++ b/examples/shell/telink/README.md @@ -4,6 +4,17 @@ You can use this example as a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -12,7 +23,7 @@ You can use this example as a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -24,8 +35,8 @@ You can use this example as a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -35,9 +46,12 @@ You can use this example as a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -55,3 +69,5 @@ To get output from device, connect UART to following pins: | RX | PB3 (pin 17 of J34 connector) | | TX | PB2 (pin 16 of J34 connector) | | GND | GND | + +Baud rate: 115200 bits/s diff --git a/examples/smoke-co-alarm-app/telink/README.md b/examples/smoke-co-alarm-app/telink/README.md index 97a00f8d53a8ad..da8a084f4dfa4f 100755 --- a/examples/smoke-co-alarm-app/telink/README.md +++ b/examples/smoke-co-alarm-app/telink/README.md @@ -4,6 +4,17 @@ You can use this example as a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -12,7 +23,7 @@ You can use this example as a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -24,8 +35,8 @@ You can use this example as a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -35,9 +46,12 @@ You can use this example as a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -56,16 +70,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Self test | Start self testing | -| Button 3 | NA | NA | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Self test | Start self testing | +| Button 3 | NA | NA | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/temperature-measurement-app/telink/README.md b/examples/temperature-measurement-app/telink/README.md index c78bd36ea8e4a6..04668c02cb0fc8 100644 --- a/examples/temperature-measurement-app/telink/README.md +++ b/examples/temperature-measurement-app/telink/README.md @@ -8,6 +8,17 @@ creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -16,7 +27,7 @@ creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -28,8 +39,8 @@ creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -39,9 +50,12 @@ creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -60,16 +74,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | NA | NA | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | NA | NA | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/thermostat/telink/README.md b/examples/thermostat/telink/README.md index 604a917ff18ce9..1d6c66bb74cd7f 100755 --- a/examples/thermostat/telink/README.md +++ b/examples/thermostat/telink/README.md @@ -4,6 +4,17 @@ You can use this example as a reference for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -12,7 +23,7 @@ You can use this example as a reference for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -24,8 +35,8 @@ You can use this example as a reference for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -35,9 +46,12 @@ You can use this example as a reference for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -56,16 +70,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | NA | NA | -| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | -| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Name | Function | Description | +| :------- | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | NA | NA | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | ### LEDs diff --git a/examples/window-app/telink/README.md b/examples/window-app/telink/README.md index 9d35cbc2d5a360..ee788a7b018f13 100644 --- a/examples/window-app/telink/README.md +++ b/examples/window-app/telink/README.md @@ -7,6 +7,17 @@ for creating your own application. ![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) +## Supported devices + +The example supports building and running on the following devices: + +| Board/SoC | Build target | Zephyr Board Info | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [B91](https://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide) [TLSR9518ADK80D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series) | `tlsr9518adk80d`, `tlsr9518adk80d-mars`, `tlsr9518adk80d-usb` | [TLSR9518ADK80D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9518adk80d/doc/index.rst) | +| [B92](https://wiki.telink-semi.cn/wiki/Hardware/B92_Generic_Starter_Kit_Hardware_Guide) [TLSR9528A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR952x-Series) | `tlsr9528a`, `tlsr9528a_retention` | [TLSR9528A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9528a/doc/index.rst) | +| [B95](https://wiki.telink-semi.cn/wiki/Hardware/B95_Generic_Starter_Kit_Hardware_Guide) [TLSR9258A](https://wiki.telink-semi.cn/wiki/chip-series/TLSR925x-Series) | `tlsr9258a` | [TLSR9258A](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9258a/doc/index.rst) | +| [W91](https://wiki.telink-semi.cn/wiki/Hardware/W91_Generic_Starter_Kit_Hardware_Guide) [TLSR9118BDK40D](https://wiki.telink-semi.cn/wiki/chip-series/TLSR911x-Series) | `tlsr9118bdk40d` | [TLSR9118BDK40D](https://github.com/telink-semi/zephyr/blob/develop/boards/riscv/tlsr9118bdk40d/doc/index.rst) | + ## Build and flash 1. Run the Docker container: @@ -15,7 +26,7 @@ for creating your own application. $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}') ``` - Compatible docker image version can be found in next file: + You can find the compatible Docker image version in the file: ```bash $ .github/workflows/examples-telink.yaml @@ -27,8 +38,8 @@ for creating your own application. $ source ./scripts/activate.sh -p all,telink ``` -3. In the example dir run (replace __ with your board name, for - example, `tlsr9118bdk40d`, `tlsr9518adk80d`, `tlsr9528a` or `tlsr9258a`): +3. Build the example (replace __ with your board name, see + [Supported devices](#supported-devices)): ```bash $ west build -b @@ -38,9 +49,12 @@ for creating your own application. MB, for example, `-DFLASH_SIZE=1m` or `-DFLASH_SIZE=4m`: ```bash - $ west build -b tlsr9518adk80d -- -DFLASH_SIZE=4m + $ west build -b -- -DFLASH_SIZE=4m ``` + You can find the target built file called **_zephyr.bin_** under the + **_build/zephyr_** directory. + 4. Flash binary: ``` @@ -59,16 +73,18 @@ To get output from device, connect UART to following pins: | TX | PB2 (pin 16 of J34 connector) | | GND | GND | +Baud rate: 115200 bits/s + ### Buttons The following buttons are available on **tlsr9518adk80d** board: -| Name | Function | Description | -| :------- | :-------------------------------- | :------------------------------------------------------------------------------------------------------------------- | -| Button 1 | Factory reset | Triple press performs factory reset to forget currently commissioned Thread network and back to uncommissioned state | -| Button 2 | Open and Toggle Move Type control | Manually triggers the Open state by one press and double press triggers the Lift-Tilt move type | -| Button 3 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | -| Button 4 | Close control | Manually triggers the Close state by one press | +| Name | Function | Description | +| :------- | :-------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and return to a decommissioned state (to activate, push the button 3 times) | +| Button 2 | Open and Toggle Move Type control | Manually triggers the Open state by one press and double press triggers the Lift-Tilt move type | +| Button 3 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | +| Button 4 | Close control | Manually triggers the Close state by one press | ### LEDs @@ -254,9 +270,9 @@ application of OTA image. The RPCs in `lighting-common/lighting_service/lighting_service.proto` can be used to control various functionalities of the lighting app from a USB-connected host computer. To build the example with the RPC server, run the following -command with _build-target_ replaced with the build target name of the Nordic +command with __ replaced with the build target name of the Telink Semiconductor's kit you own: ``` - $ west build -b tlsr9518adk80d -- -DOVERLAY_CONFIG=rpc.overlay + $ west build -b -- -DOVERLAY_CONFIG=rpc.overlay ``` diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 97f8e90af507d5..2c5f84ca30ad37 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -784,6 +784,7 @@ def BuildTelinkTarget(): target.AppendModifier('factory-data', enable_factory_data=True) target.AppendModifier('4mb', enable_4mb_flash=True) target.AppendModifier('mars', mars_board_config=True) + target.AppendModifier('usb', usb_board_config=True) return target diff --git a/scripts/build/builders/telink.py b/scripts/build/builders/telink.py index c53e0b6321cd76..b9cd709ba6b44c 100644 --- a/scripts/build/builders/telink.py +++ b/scripts/build/builders/telink.py @@ -151,7 +151,8 @@ def __init__(self, enable_rpcs: bool = False, enable_factory_data: bool = False, enable_4mb_flash: bool = False, - mars_board_config: bool = False): + mars_board_config: bool = False, + usb_board_config: bool = False): super(TelinkBuilder, self).__init__(root, runner) self.app = app self.board = board @@ -162,6 +163,7 @@ def __init__(self, self.enable_factory_data = enable_factory_data self.enable_4mb_flash = enable_4mb_flash self.mars_board_config = mars_board_config + self.usb_board_config = usb_board_config def get_cmd_prefixes(self): if not self._runner.dry_run: @@ -203,6 +205,9 @@ def generate(self): if self.mars_board_config: flags.append("-DTLNK_MARS_BOARD=y") + if self.usb_board_config: + flags.append("-DTLNK_USB_DONGLE=y") + if self.options.pregen_dir: flags.append(f"-DCHIP_CODEGEN_PREGEN_DIR={shlex.quote(self.options.pregen_dir)}") diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index 2d9fee76e68ac0..d391093a153fcf 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -23,5 +23,5 @@ nuttx-x64-light qpg-qpg6105-{lock,light,shell,persistent-storage,light-switch,thermostat}[-updateimage] stm32-stm32wb5mm-dk-light tizen-arm-{all-clusters,all-clusters-minimal,chip-tool,light,tests}[-no-ble][-no-thread][-no-wifi][-asan][-ubsan][-with-ui] -telink-{tlsr9118bdk40d,tlsr9518adk80d,tlsr9528a,tlsr9528a_retention,tlsr9258a,tlsr9258a_retention}-{air-quality-sensor,all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-ota][-dfu][-shell][-rpc][-factory-data][-4mb][-mars] +telink-{tlsr9118bdk40d,tlsr9518adk80d,tlsr9528a,tlsr9528a_retention,tlsr9258a,tlsr9258a_retention}-{air-quality-sensor,all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-ota][-dfu][-shell][-rpc][-factory-data][-4mb][-mars][-usb] openiotsdk-{shell,lock}[-mbedtls][-psa] From 04fbb8f490b5db5b4a68951f5f404548440ccbe3 Mon Sep 17 00:00:00 2001 From: PeterC1965 <101805108+PeterC1965@users.noreply.github.com> Date: Fri, 26 Jul 2024 01:48:14 +0100 Subject: [PATCH 11/17] Add device-energy-management cluster example app code for 1.4 (#33910) * Get the EVSE app building and test TC_DEM_2_2 passing * Get all targets building * Address JamesH review comments * Rename utils.cpp to DEMUtils.cpp * Address JamesH review comments * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Restyled by prettier-markdown * Restyled by autopep8 * Restyled by isort * Fix compilation problem by including lib/core/DataModelTypes.h * Fix compilation problem by including * Save examples/all-clusters-app/all-clusters-common/all-clusters-app.zap to update it * Restyled by clang-format * Apply further code review changes * Restyled by clang-format * Restyled by gn * Address code review comments from AndreiL * Restyled by whitespace * Restyled by clang-format * Fix ESP build * Fix ESP build * Restyled by clang-format * Rename src/python_testing/TC_DEM_Utils.py src/python_testing/DEMTestBase.py * Put time util funtions into namespace + drop the Utils prefix * Restyled by whitespace * Restyled by isort * Try to address setForecast comments from Boris * Remove unnecessary SetXXX methods from the device energy management cluster interface * Restyled by clang-format * Apply code review changes suggested by Louis-Philip Beliveau * Document the API for GetForecast and GetPowerAdjustmentCapability * Document the GetForecast and GetPowerAdjustmentCapability APIs * Update src/app/clusters/device-energy-management-server/device-energy-management-server.h Co-authored-by: Boris Zbarsky * Update src/app/clusters/device-energy-management-server/device-energy-management-server.h Co-authored-by: Boris Zbarsky * Address review comments from Boris * Sync up with code review comments from PR34234 * Sync up with code review comments from PR34234 that caused some return codes to change * Restyled by clang-format * modifyForecastRequest: Failure should be returned if a slot number > num slots in a forecast * Update examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/include/EVSECallbacks.h Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp Co-authored-by: Boris Zbarsky * Address review comments from Boris * Update examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp Co-authored-by: Boris Zbarsky * Address further review comments from Boris * Address further review comments from Boris * Address further review comments from Boris * Update examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp Co-authored-by: Boris Zbarsky * Address further review comments from Boris * Update examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp Co-authored-by: Boris Zbarsky * Apply further review comments from Boris * Used a bitmap rather than uint8_t and sync EnergyTimeUtils files from the EVSE_Add_Get_Set_Clear_Targets_Support branch * Update following review comments from Boris * Allow more time for forecast.startTime in test setup as tests can take variable lengths of time to run * Update examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp Co-authored-by: Boris Zbarsky * Update examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp Co-authored-by: Boris Zbarsky * Addressing further review comments from Boris * Fix small issue found as a result of the DEM test script review * Protect against forecast being null * Remove src/python_testing/DEMTestBase.py as renamed in PR34234 * Update following review comment from Andrei * Restyled by clang-format --------- Co-authored-by: Restyled.io Co-authored-by: Boris Zbarsky --- .../all-clusters-app/ameba/chip_main.cmake | 2 + examples/all-clusters-app/asr/BUILD.gn | 2 + .../all-clusters-app/cc13x4_26x4/BUILD.gn | 2 + .../all-clusters-app/infineon/psoc6/BUILD.gn | 2 + examples/all-clusters-app/linux/BUILD.gn | 2 + examples/all-clusters-app/mbed/CMakeLists.txt | 7 +- .../nrfconnect/CMakeLists.txt | 6 +- examples/all-clusters-app/nxp/mw320/BUILD.gn | 2 + .../openiotsdk/CMakeLists.txt | 10 +- .../all-clusters-app/telink/CMakeLists.txt | 10 +- examples/all-clusters-app/tizen/BUILD.gn | 2 + .../energy-management-common/BUILD.gn | 2 +- .../include/DEMManufacturerDelegate.h | 88 ++ .../DeviceEnergyManagementDelegateImpl.h | 287 ++++++- .../include/DeviceEnergyManagementManager.h | 10 +- .../include/EVSECallbacks.h | 2 +- .../include/EVSEManufacturerImpl.h | 48 +- .../include/EnergyEvseDelegateImpl.h | 9 +- .../include/EnergyEvseManager.h | 2 +- .../EnergyManagementAppCmdLineOptions.h | 34 + .../include/EnergyTimeUtils.h | 74 ++ .../include/FakeReadings.h | 115 +++ .../src/DEMTestEventTriggers.cpp | 386 +++++++++ .../DeviceEnergyManagementDelegateImpl.cpp | 751 ++++++++++++++++-- .../src/DeviceEnergyManagementManager.cpp | 16 +- .../src/EVSEManufacturerImpl.cpp | 376 +-------- .../src/EnergyEvseDelegateImpl.cpp | 2 +- .../src/EnergyEvseEventTriggers.cpp | 184 +++++ .../src/EnergyEvseMain.cpp | 18 +- .../src/EnergyEvseManager.cpp | 2 +- .../src/EnergyReportingEventTriggers.cpp | 85 ++ .../src/EnergyTimeUtils.cpp | 153 ++++ .../src/FakeReadings.cpp | 176 ++++ .../esp32/main/CMakeLists.txt | 1 + .../esp32/main/include/CHIPProjectConfig.h | 2 +- .../energy-management-app/esp32/main/main.cpp | 20 + .../esp32/sdkconfig.optimize.defaults | 2 +- examples/energy-management-app/linux/BUILD.gn | 7 +- .../energy-management-app/linux/README.md | 47 ++ examples/energy-management-app/linux/args.gni | 3 +- examples/energy-management-app/linux/main.cpp | 89 ++- examples/platform/linux/AppMain.cpp | 7 + examples/platform/linux/BUILD.gn | 7 + examples/shell/shell_common/BUILD.gn | 3 + src/app/chip_data_model.gni | 6 + .../device-energy-management-server.cpp | 8 +- .../device-energy-management-server.h | 52 +- src/python_testing/TC_DEM_2_2.py | 367 +++++++++ src/python_testing/matter_testing_support.py | 18 +- 49 files changed, 3002 insertions(+), 504 deletions(-) mode change 100755 => 100644 examples/all-clusters-app/ameba/chip_main.cmake mode change 100755 => 100644 examples/all-clusters-app/asr/BUILD.gn create mode 100644 examples/energy-management-app/energy-management-common/include/DEMManufacturerDelegate.h create mode 100644 examples/energy-management-app/energy-management-common/include/EnergyManagementAppCmdLineOptions.h create mode 100644 examples/energy-management-app/energy-management-common/include/EnergyTimeUtils.h create mode 100644 examples/energy-management-app/energy-management-common/include/FakeReadings.h create mode 100644 examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/EnergyEvseEventTriggers.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/EnergyReportingEventTriggers.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/FakeReadings.cpp create mode 100644 src/python_testing/TC_DEM_2_2.py diff --git a/examples/all-clusters-app/ameba/chip_main.cmake b/examples/all-clusters-app/ameba/chip_main.cmake old mode 100755 new mode 100644 index 00358771e5adbf..ce557a2bffaf30 --- a/examples/all-clusters-app/ameba/chip_main.cmake +++ b/examples/all-clusters-app/ameba/chip_main.cmake @@ -187,8 +187,10 @@ list( ${chip_dir}/examples/microwave-oven-app/microwave-oven-common/src/microwave-oven-device.cpp + ${chip_dir}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp + ${chip_dir}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp ${chip_dir}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp diff --git a/examples/all-clusters-app/asr/BUILD.gn b/examples/all-clusters-app/asr/BUILD.gn old mode 100755 new mode 100644 index 6b016c5d81119c..6c9d334a1ed6c2 --- a/examples/all-clusters-app/asr/BUILD.gn +++ b/examples/all-clusters-app/asr/BUILD.gn @@ -84,9 +84,11 @@ asr_executable("clusters_app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", "${examples_plat_dir}/ButtonHandler.cpp", "${examples_plat_dir}/CHIPDeviceManager.cpp", "${examples_plat_dir}/LEDWidget.cpp", diff --git a/examples/all-clusters-app/cc13x4_26x4/BUILD.gn b/examples/all-clusters-app/cc13x4_26x4/BUILD.gn index 2a5609fb98b928..45efe2d45e9bce 100644 --- a/examples/all-clusters-app/cc13x4_26x4/BUILD.gn +++ b/examples/all-clusters-app/cc13x4_26x4/BUILD.gn @@ -74,9 +74,11 @@ ti_simplelink_executable("all-clusters-app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", "${chip_root}/examples/providers/DeviceInfoProviderImpl.cpp", "${chip_root}/src/app/clusters/general-diagnostics-server/GenericFaultTestEventTriggerHandler.cpp", "${project_dir}/main/AppTask.cpp", diff --git a/examples/all-clusters-app/infineon/psoc6/BUILD.gn b/examples/all-clusters-app/infineon/psoc6/BUILD.gn index aab6fdfd275986..2c0b0a6fee7dfa 100644 --- a/examples/all-clusters-app/infineon/psoc6/BUILD.gn +++ b/examples/all-clusters-app/infineon/psoc6/BUILD.gn @@ -126,9 +126,11 @@ psoc6_executable("clusters_app") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", "${examples_plat_dir}/LEDWidget.cpp", "${examples_plat_dir}/init_psoc6Platform.cpp", "src/AppTask.cpp", diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index a2f4ff0ab1f781..e71574ce4db5ac 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -60,9 +60,11 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/linux/diagnostic-logs-provider-delegate-impl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/device-energy-management-mode.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/energy-evse-mode.cpp", "AllClustersCommandDelegate.cpp", diff --git a/examples/all-clusters-app/mbed/CMakeLists.txt b/examples/all-clusters-app/mbed/CMakeLists.txt index 3d1a179a93bbb2..9b490ff687d1e3 100644 --- a/examples/all-clusters-app/mbed/CMakeLists.txt +++ b/examples/all-clusters-app/mbed/CMakeLists.txt @@ -72,12 +72,13 @@ target_sources(${APP_TARGET} PRIVATE ${ALL_CLUSTERS_COMMON}/src/smco-stub.cpp ${ALL_CLUSTERS_COMMON}/src/static-supported-modes-manager.cpp ${ALL_CLUSTERS_COMMON}/src/static-supported-temperature-levels.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/EnergyTimeUtils.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementManager.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/EVSEManufacturerImpl.cpp ${ENERGY_MANAGEMENT_COMMON}/src/ElectricalPowerMeasurementDelegate.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseManager.cpp - ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementDelegateImpl.cpp - ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementManager.cpp - ) chip_configure_data_model(${APP_TARGET} diff --git a/examples/all-clusters-app/nrfconnect/CMakeLists.txt b/examples/all-clusters-app/nrfconnect/CMakeLists.txt index 8b5c3c1c9e72fd..c290003532a431 100644 --- a/examples/all-clusters-app/nrfconnect/CMakeLists.txt +++ b/examples/all-clusters-app/nrfconnect/CMakeLists.txt @@ -42,7 +42,7 @@ include(${CHIP_ROOT}/src/app/chip_data_model.cmake) target_include_directories(app PRIVATE main/include ${ALL_CLUSTERS_COMMON_DIR}/include - ${ENERGY_MANAGEMENT_COMMON_DIR}/include + ${ENERGY_MANAGEMENT_COMMON_DIR}/include ${GEN_DIR}/app-common ${GEN_DIR}/all-clusters-app ${NRFCONNECT_COMMON}/util/include) @@ -57,13 +57,15 @@ target_sources(app PRIVATE ${ALL_CLUSTERS_COMMON_DIR}/src/fan-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/oven-modes.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/energy-evse-stub.cpp - ${ALL_CLUSTERS_COMMON_DIR}/src/device-energy-management-stub.cpp + ${ALL_CLUSTERS_COMMON_DIR}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/binding-handler.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/air-quality-instance.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/resource-monitoring-delegates.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyTimeUtils.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementManager.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EVSEManufacturerImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/ElectricalPowerMeasurementDelegate.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseManager.cpp diff --git a/examples/all-clusters-app/nxp/mw320/BUILD.gn b/examples/all-clusters-app/nxp/mw320/BUILD.gn index ebae8c34bccdee..83877a175993df 100644 --- a/examples/all-clusters-app/nxp/mw320/BUILD.gn +++ b/examples/all-clusters-app/nxp/mw320/BUILD.gn @@ -91,9 +91,11 @@ mw320_executable("shell_mw320") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", "${chip_root}/src/lib/shell/streamer_mw320.cpp", "binding-handler.cpp", "include/CHIPProjectConfig.h", diff --git a/examples/all-clusters-app/openiotsdk/CMakeLists.txt b/examples/all-clusters-app/openiotsdk/CMakeLists.txt index 6d2fb76c0db919..1395cf170a8b79 100644 --- a/examples/all-clusters-app/openiotsdk/CMakeLists.txt +++ b/examples/all-clusters-app/openiotsdk/CMakeLists.txt @@ -48,7 +48,7 @@ target_include_directories(${APP_TARGET} PRIVATE main/include ${ALL_CLUSTERS_COMMON}/include - ${ENERGY_MANAGEMENT_COMMON}/include + ${ENERGY_MANAGEMENT_COMMON}/include ) target_sources(${APP_TARGET} @@ -60,16 +60,18 @@ target_sources(${APP_TARGET} ${ALL_CLUSTERS_COMMON}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON}/src/fan-stub.cpp ${ALL_CLUSTERS_COMMON}/src/oven-modes.cpp - ${ALL_CLUSTERS_COMMON}/src/device-energy-management-stub.cpp + ${ALL_CLUSTERS_COMMON}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON}/src/energy-evse-stub.cpp ${ALL_CLUSTERS_COMMON}/src/resource-monitoring-delegates.cpp ${ALL_CLUSTERS_COMMON}/src/static-supported-modes-manager.cpp ${ALL_CLUSTERS_COMMON}/src/binding-handler.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/EnergyTimeUtils.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementManager.cpp + ${ENERGY_MANAGEMENT_COMMON}/src/EVSEManufacturerImpl.cpp ${ENERGY_MANAGEMENT_COMMON}/src/ElectricalPowerMeasurementDelegate.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON}/src/EnergyEvseManager.cpp - ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementDelegateImpl.cpp - ${ENERGY_MANAGEMENT_COMMON}/src/DeviceEnergyManagementManager.cpp ) target_link_libraries(${APP_TARGET} diff --git a/examples/all-clusters-app/telink/CMakeLists.txt b/examples/all-clusters-app/telink/CMakeLists.txt index d5f2132c9d2747..149b38e3528cce 100644 --- a/examples/all-clusters-app/telink/CMakeLists.txt +++ b/examples/all-clusters-app/telink/CMakeLists.txt @@ -31,7 +31,7 @@ project(chip-telink-all-clusters-app-example) target_include_directories(app PRIVATE include ${ALL_CLUSTERS_COMMON_DIR}/include - ${ENERGY_MANAGEMENT_COMMON_DIR}/include + ${ENERGY_MANAGEMENT_COMMON_DIR}/include ${GEN_DIR}/app-common ${GEN_DIR}/all-clusters-app ${TELINK_COMMON}/common/include @@ -48,14 +48,16 @@ target_sources(app PRIVATE ${ALL_CLUSTERS_COMMON_DIR}/src/air-quality-instance.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/concentration-measurement-instances.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/fan-stub.cpp - ${ALL_CLUSTERS_COMMON_DIR}/src/device-energy-management-stub.cpp + ${ALL_CLUSTERS_COMMON_DIR}/src/device-energy-management-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/energy-evse-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/resource-monitoring-delegates.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyTimeUtils.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementDelegateImpl.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementManager.cpp + ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EVSEManufacturerImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/ElectricalPowerMeasurementDelegate.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseDelegateImpl.cpp ${ENERGY_MANAGEMENT_COMMON_DIR}/src/EnergyEvseManager.cpp - ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementDelegateImpl.cpp - ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementManager.cpp ${TELINK_COMMON}/common/src/mainCommon.cpp ${TELINK_COMMON}/common/src/AppTaskCommon.cpp ${TELINK_COMMON}/util/src/LEDManager.cpp diff --git a/examples/all-clusters-app/tizen/BUILD.gn b/examples/all-clusters-app/tizen/BUILD.gn index 364e9ce857d5da..9aff82b57b2876 100644 --- a/examples/all-clusters-app/tizen/BUILD.gn +++ b/examples/all-clusters-app/tizen/BUILD.gn @@ -40,9 +40,11 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", ] deps = [ diff --git a/examples/energy-management-app/energy-management-common/BUILD.gn b/examples/energy-management-app/energy-management-common/BUILD.gn index 937aca9f1746d0..e6b67461f40a3b 100644 --- a/examples/energy-management-app/energy-management-common/BUILD.gn +++ b/examples/energy-management-app/energy-management-common/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Project CHIP Authors +# Copyright (c) 2023-2024 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. diff --git a/examples/energy-management-app/energy-management-common/include/DEMManufacturerDelegate.h b/examples/energy-management-app/energy-management-common/include/DEMManufacturerDelegate.h new file mode 100644 index 00000000000000..65d214d31904ab --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/DEMManufacturerDelegate.h @@ -0,0 +1,88 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +/** + * Class to abstract manufacturer specific functionality + */ +class DEMManufacturerDelegate +{ +public: + DEMManufacturerDelegate() {} + + virtual ~DEMManufacturerDelegate() {} + + // The PowerAdjustEnd event needs to report the approximate energy used by the ESA during the session. + virtual int64_t GetApproxEnergyDuringSession() = 0; + + virtual CHIP_ERROR HandleDeviceEnergyManagementPowerAdjustRequest(const int64_t powerMw, const uint32_t durationS, + AdjustmentCauseEnum cause) + { + return CHIP_NO_ERROR; + } + + virtual CHIP_ERROR HandleDeviceEnergyManagementPowerAdjustCompletion() { return CHIP_NO_ERROR; } + + virtual CHIP_ERROR HandleDeviceEnergyManagementCancelPowerAdjustRequest(CauseEnum cause) { return CHIP_NO_ERROR; } + + virtual CHIP_ERROR HandleDeviceEnergyManagementStartTimeAdjustRequest(const uint32_t requestedStartTimeUtc, + AdjustmentCauseEnum cause) + { + return CHIP_NO_ERROR; + } + + virtual CHIP_ERROR HandleDeviceEnergyManagementPauseRequest(const uint32_t durationS, AdjustmentCauseEnum cause) + { + return CHIP_NO_ERROR; + } + + virtual CHIP_ERROR HandleDeviceEnergyManagementPauseCompletion() { return CHIP_NO_ERROR; } + + virtual CHIP_ERROR HandleDeviceEnergyManagementCancelPauseRequest(CauseEnum cause) { return CHIP_NO_ERROR; } + + virtual CHIP_ERROR HandleDeviceEnergyManagementCancelRequest() { return CHIP_NO_ERROR; } + + virtual CHIP_ERROR + HandleModifyForecastRequest(const uint32_t forecastID, + const DataModel::DecodableList & slotAdjustments, + AdjustmentCauseEnum cause) + { + return CHIP_NO_ERROR; + } + + virtual CHIP_ERROR RequestConstraintBasedForecast( + const DataModel::DecodableList & constraints, + AdjustmentCauseEnum cause) + { + return CHIP_NO_ERROR; + } +}; + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h index 1248fc405a3c8a..e540d56e030058 100644 --- a/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h +++ b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementDelegateImpl.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,12 +18,10 @@ #pragma once -#include "app/clusters/device-energy-management-server/device-energy-management-server.h" - +#include +#include #include -#include -using chip::Protocols::InteractionModel::Status; namespace chip { namespace app { namespace Clusters { @@ -35,52 +33,267 @@ namespace DeviceEnergyManagement { class DeviceEnergyManagementDelegate : public DeviceEnergyManagement::Delegate { public: - virtual Status PowerAdjustRequest(const int64_t power, const uint32_t duration, AdjustmentCauseEnum cause) override; - virtual Status CancelPowerAdjustRequest() override; - virtual Status StartTimeAdjustRequest(const uint32_t requestedStartTime, AdjustmentCauseEnum cause) override; - virtual Status PauseRequest(const uint32_t duration, AdjustmentCauseEnum cause) override; - virtual Status ResumeRequest() override; - virtual Status - ModifyForecastRequest(const uint32_t forecastId, + DeviceEnergyManagementDelegate(); + + void SetDeviceEnergyManagementInstance(DeviceEnergyManagement::Instance & instance); + + void SetDEMManufacturerDelegate(DEMManufacturerDelegate & deviceEnergyManagementManufacturerDelegate); + + /** + * + * Implement the DeviceEnergyManagement::Delegate interface + * + */ + + /** + * @brief Implements a handler to begin to adjust client power + * consumption/generation to the level requested. + * + * Note callers must call GetPowerAdjustmentCapability and ensure the return value is not null + * before calling PowerAdjustRequest. + * + * @param power Milli-Watts the ESA SHALL use during the adjustment period. + * @param duration The duration that the ESA SHALL maintain the requested power for. + * @return Success if the adjustment is accepted; otherwise the command SHALL be rejected with appropriate error. + */ + chip::Protocols::InteractionModel::Status PowerAdjustRequest(const int64_t powerMw, const uint32_t durationS, + AdjustmentCauseEnum cause) override; + + /** + * @brief Make the ESA end the active power adjustment session & return to normal (or idle) power levels. + * The ESA SHALL also generate an PowerAdjustEnd Event and the ESAState SHALL be restored to Online. + * + * @return It should report SUCCESS if successful and FAILURE otherwise. + */ + chip::Protocols::InteractionModel::Status CancelPowerAdjustRequest() override; + + /** + * @brief The ESA SHALL update its Forecast attribute with the RequestedStartTime including a new ForecastID. + * + * If the ESA supports ForecastAdjustment, and the ESAState is not UserOptOut and the RequestedStartTime is after + * the EarliestStartTime and the resulting EndTime is before the LatestEndTime, then ESA SHALL accept the request + * to modify the Start Time. + * A client can estimate the entire Forecast sequence duration by computing the EndTime - StartTime fields from the + * Forecast attribute, and therefore avoid scheduling the start time too late. + * + * @param requestedStartTime The requested start time in UTC that the client would like the appliance to shift its power + * forecast to. + * @param cause Who (Grid/local) is triggering this change. + * + * @return Success if the StartTime in the Forecast is updated, otherwise the command SHALL be rejected with appropriate + * IM_Status. + */ + chip::Protocols::InteractionModel::Status StartTimeAdjustRequest(const uint32_t requestedStartTimeUtc, + AdjustmentCauseEnum cause) override; + + /** + * @brief Handler for PauseRequest command + * + * If the ESA supports FA and the SlotIsPauseable field is true in the ActiveSlotNumber + * index in the Slots list, and the ESAState is not UserOptOut then the ESA SHALL allow its current + * operation to be Paused. + * + * During this state the ESA SHALL not consume or produce significant power (other than required to keep its + * basic control system operational). + * + * @param duration Duration that the ESA SHALL be paused for. + * @return Success if the ESA is paused, otherwise returns other IM_Status. + */ + chip::Protocols::InteractionModel::Status PauseRequest(const uint32_t durationS, AdjustmentCauseEnum cause) override; + + /** + * @brief Handler for ResumeRequest command + * + * If the ESA supports FA and it is currently Paused then the ESA SHALL resume its operation. + * The ESA SHALL also generate a Resumed Event and the ESAState SHALL be updated accordingly to + * reflect its current state. + * + * @return Success if the ESA is resumed, otherwise returns other IM_Status. + */ + chip::Protocols::InteractionModel::Status ResumeRequest() override; + + /** + * @brief Handler for ModifyForecastRequest + * + * If the ESA supports FA, and the ESAState is not UserOptOut it SHALL attempt to adjust its power forecast. + * This allows a one or more modifications in a single command by sending a list of modifications (one for each 'slot'). + * Attempts to modify slots which have already past, SHALL result in the entire command being rejected. + * If the ESA accepts the requested Forecast then it SHALL update its Forecast attribute (incrementing its ForecastID) + * and run the revised Forecast as its new intended operation. + * + * *** NOTE *** for the memory management of the forecast object, see the comment before the mForecast delaration below. + * + * @param forecastID Indicates the ESA ForecastID that is to be modified. + * @param slotAdjustments List of adjustments to be applied to the ESA, corresponding to the expected ESA forecastID. + * @return Success if the entire list of SlotAdjustmentStruct are accepted, otherwise the command + * SHALL be rejected returning other IM_Status. + */ + chip::Protocols::InteractionModel::Status + ModifyForecastRequest(const uint32_t forecastID, const DataModel::DecodableList & slotAdjustments, AdjustmentCauseEnum cause) override; - virtual Status + + /** + * @brief Handler for RequestConstraintBasedForecast + * + * The ESA SHALL inspect the requested power limits to ensure that there are no overlapping elements. The ESA + * manufacturer may also reject the request if it could cause the user’s preferences to be breached (e.g. may + * cause the home to be too hot or too cold, or a battery to be insufficiently charged). + * If the ESA can meet the requested power limits, it SHALL regenerate a new Power Forecast with a new ForecastID. + * + * @param constraints Sequence of turn up/down power requests that the ESA is being asked to constrain its operation within. + * @return Success if successful, otherwise the command SHALL be rejected returning other IM_Status. + */ + chip::Protocols::InteractionModel::Status RequestConstraintBasedForecast(const DataModel::DecodableList & constraints, AdjustmentCauseEnum cause) override; - virtual Status CancelRequest() override; + + /** + * @brief Handler for CancelRequest + * + * The ESA SHALL attempt to cancel the effects of any previous adjustment request commands, and re-evaluate its + * forecast for intended operation ignoring those previous requests. + * + * If the ESA ForecastStruct ForecastUpdateReason was already `Internal Optimization`, then the command SHALL + * be rejected with FAILURE. + * + * If the command is accepted, the ESA SHALL update its ESAState if required, and the command status returned + * SHALL be SUCCESS. + * + * The ESA SHALL update its Forecast attribute to match its new intended operation, and update the + * ForecastStruct.ForecastUpdateReason to `Internal Optimization` + * + * @return Success if successful, otherwise the command SHALL be rejected returning other IM_Status. + */ + chip::Protocols::InteractionModel::Status CancelRequest() override; // ------------------------------------------------------------------ - // Get attribute methods - virtual ESATypeEnum GetESAType() override; - virtual bool GetESACanGenerate() override; - virtual ESAStateEnum GetESAState() override; - virtual int64_t GetAbsMinPower() override; - virtual int64_t GetAbsMaxPower() override; - virtual Attributes::PowerAdjustmentCapability::TypeInfo::Type GetPowerAdjustmentCapability() override; - virtual DataModel::Nullable GetForecast() override; - virtual OptOutStateEnum GetOptOutState() override; + // Overridden DeviceEnergyManagement::Delegate Get attribute methods + + ESATypeEnum GetESAType() override; + bool GetESACanGenerate() override; + ESAStateEnum GetESAState() override; + int64_t GetAbsMinPower() override; + int64_t GetAbsMaxPower() override; + const DataModel::Nullable & GetPowerAdjustmentCapability() override; + const DataModel::Nullable & GetForecast() override; + OptOutStateEnum GetOptOutState() override; // ------------------------------------------------------------------ - // Set attribute methods - virtual CHIP_ERROR SetESAType(ESATypeEnum) override; - virtual CHIP_ERROR SetESACanGenerate(bool) override; - virtual CHIP_ERROR SetESAState(ESAStateEnum) override; - virtual CHIP_ERROR SetAbsMinPower(int64_t) override; - virtual CHIP_ERROR SetAbsMaxPower(int64_t) override; - virtual CHIP_ERROR SetPowerAdjustmentCapability(Attributes::PowerAdjustmentCapability::TypeInfo::Type) override; - virtual CHIP_ERROR SetForecast(DataModel::Nullable) override; - virtual CHIP_ERROR SetOptOutState(OptOutStateEnum) override; + // Overridden DeviceEnergyManagement::Delegate Set attribute methods + CHIP_ERROR SetESAState(ESAStateEnum) override; + + // Local Set methods + CHIP_ERROR SetESAType(ESATypeEnum); + CHIP_ERROR SetESACanGenerate(bool); + CHIP_ERROR SetAbsMinPower(int64_t); + CHIP_ERROR SetAbsMaxPower(int64_t); + CHIP_ERROR SetPowerAdjustmentCapability(const DataModel::Nullable &); + + // The DeviceEnergyManagementDelegate owns the master copy of the ForecastStruct object which is accessed via GetForecast and + // SetForecast. The slots field of forecast is owned and managed by the object that implements the DEMManufacturerDelegate + // interface. The slots memory MUST exist for the lifetime of the forecast object from where it is referenced. + // + // The rationale for this is as follows: + // It is envisioned there will be one master forecast object declared in DeviceEnergyManagementDelegate. When + // constructed, the field DataModel::List slots will be empty. + // + // The EVSEManufacturerImpl class (examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h) is + // an example implementation that a specific vendor can use as a template. It understands how the underlying energy appliance + // functions. EVSEManufacturerImpl inherits from DEMManufacturerDelegate + // (examples/energy-management-app/energy-management-common/include/DEMManufacturerDelegate.h) which is a generic interface + // and how the DeviceEnergyManagementDelegate class + // (examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp) communicates from the + // generic cluster world to the specific appliance implementation (EVSEManufacturerImpl). + // + // EVSEManufacturerImpl understands the slot structures of the appliance and configures the slot structures as follows: + // + // Call DeviceEnergyManagementDelegate::GetForecast() to get the current forecast + // Modify the slot structure - the slots memory is owned by EVSEManufacturerImpl + // Call DeviceEnergyManagementDelegate::GetForecast() to set the current forecast + // + // + // The cluster object DeviceEnergyManagement::Instance + // (src/app/clusters/device-energy-management-server/device-energy-management-server.cpp) only reads the slots field of + // forecast when checking commands (indeed it does not modify any forecast fields itself). The DeviceEnergyManagementDelegate + // object does modify some of forecast's fields but does NOT modify the slots field. The only command that can modify the + // slots field is HandleModifyForecastRequest. Whilst DeviceEnergyManagementDelegate::ModifyForecastRequest does some state + // checking, the slots field is only modified by the EVSEManufacturerImpl object via the call + // DEMManufacturerDelegate::HandleModifyForecastRequest. DEMManufacturerDelegate::HandleModifyForecastRequest may + // delete/allocate the slots memory but this will be done atomically in the call to + // DEMManufacturerDelegate::HandleModifyForecastRequest so the underlying memory is coherent => the call to + // DEMManufacturerDelegate::HandleModifyForecastRequest cannot be interrupted by any other CHIP task activity. + CHIP_ERROR SetForecast(const DataModel::Nullable &); + + CHIP_ERROR SetOptOutState(OptOutStateEnum); + + // Returns whether the DeviceEnergyManagement is supported + uint32_t HasFeature(Feature feature) const; private: + /** + * @brief Handle a PowerAdjustRequest failing + * + * Cleans up the PowerAdjust state should the request fail + */ + void HandlePowerAdjustRequestFailure(); + + // Methods to handle when a PowerAdjustment completes + static void PowerAdjustTimerExpiry(System::Layer * systemLayer, void * delegate); + void HandlePowerAdjustTimerExpiry(); + + // Method to cancel a PowerAdjustment + CHIP_ERROR CancelPowerAdjustRequestAndGenerateEvent(CauseEnum cause); + + // Method to generate a PowerAdjustEnd event + CHIP_ERROR GeneratePowerAdjustEndEvent(CauseEnum cause); + + /** + * @brief Handle a PauseRequest failing + * + * Cleans up the state should the PauseRequest fail + */ + void HandlePauseRequestFailure(); + + // Methods to handle when a PauseRequest completes + static void PauseRequestTimerExpiry(System::Layer * systemLayer, void * delegate); + void HandlePauseRequestTimerExpiry(); + + // Method to cancel a PauseRequest + CHIP_ERROR CancelPauseRequestAndGenerateEvent(CauseEnum cause); + + // Method to generate a Paused event + CHIP_ERROR GenerateResumedEvent(CauseEnum cause); + +private: + // Have a pointer to partner instance object + DeviceEnergyManagement::Instance * mpDEMInstance; + + // The DEMManufacturerDelegate object knows how to handle + // manufacturer/product specific operations + DEMManufacturerDelegate * mpDEMManufacturerDelegate; + + // Various attributes ESATypeEnum mEsaType; bool mEsaCanGenerate; ESAStateEnum mEsaState; - int64_t mAbsMinPower; - int64_t mAbsMaxPower; - Attributes::PowerAdjustmentCapability::TypeInfo::Type mPowerAdjustmentCapability; + int64_t mAbsMinPowerMw; + int64_t mAbsMaxPowerMw; + OptOutStateEnum mOptOutState; + + DataModel::Nullable mPowerAdjustCapabilityStruct; + + // See note above on SetForecast() about mForecast memory management DataModel::Nullable mForecast; - // Default to NoOptOut - OptOutStateEnum mOptOutState = OptOutStateEnum::kNoOptOut; + + // Keep track whether a PowerAdjustment is in progress + bool mPowerAdjustmentInProgress; + + // Keep track of when that PowerAdjustment started + uint32_t mPowerAdjustmentStartTimeUtc; + + // Keep track whether a PauseRequest is in progress + bool mPauseRequestInProgress; }; } // namespace DeviceEnergyManagement diff --git a/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h index aec875ff0d1f99..b7ae4565656ff3 100644 --- a/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h +++ b/examples/energy-management-app/energy-management-common/include/DeviceEnergyManagementManager.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,6 @@ #pragma once #include -#include #include #include @@ -28,14 +27,11 @@ namespace app { namespace Clusters { using namespace chip::app::Clusters::DeviceEnergyManagement; + class DeviceEnergyManagementManager : public Instance { public: - DeviceEnergyManagementManager(EndpointId aEndpointId, DeviceEnergyManagementDelegate & aDelegate, Feature aFeature) : - DeviceEnergyManagement::Instance(aEndpointId, aDelegate, aFeature) - { - mDelegate = &aDelegate; - } + DeviceEnergyManagementManager(EndpointId aEndpointId, DeviceEnergyManagementDelegate & aDelegate, Feature aFeature); // Delete copy constructor and assignment operator. DeviceEnergyManagementManager(const DeviceEnergyManagementManager &) = delete; diff --git a/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h b/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h index 7d288809952ee3..4cbee2a6b7ca9f 100644 --- a/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h +++ b/examples/energy-management-app/energy-management-common/include/EVSECallbacks.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h index 23994e7f5d9454..2faf81046cfdf2 100644 --- a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h +++ b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,7 @@ #pragma once +#include #include #include #include @@ -33,20 +34,24 @@ namespace EnergyEvse { * The EVSEManufacturer example class */ -class EVSEManufacturer +class EVSEManufacturer : public DEMManufacturerDelegate { public: EVSEManufacturer(EnergyEvseManager * aEvseInstance, ElectricalPowerMeasurement::ElectricalPowerMeasurementInstance * aEPMInstance, - PowerTopology::PowerTopologyInstance * aPTInstance) + PowerTopology::PowerTopologyInstance * aPTInstance, DeviceEnergyManagementManager * aDEMInstance) { mEvseInstance = aEvseInstance; mEPMInstance = aEPMInstance; mPTInstance = aPTInstance; + mDEMInstance = aDEMInstance; } + + virtual ~EVSEManufacturer() {} + EnergyEvseManager * GetEvseInstance() { return mEvseInstance; } + ElectricalPowerMeasurement::ElectricalPowerMeasurementInstance * GetEPMInstance() { return mEPMInstance; } - PowerTopology::PowerTopologyInstance * GetPTInstance() { return mPTInstance; } EnergyEvseDelegate * GetEvseDelegate() { @@ -75,6 +80,40 @@ class EVSEManufacturer return nullptr; } + DeviceEnergyManagementDelegate * GetDEMDelegate() + { + if (mDEMInstance) + { + return mDEMInstance->GetDelegate(); + } + return nullptr; + } + + /** + * + * Implement the DEMManufacturerDelegate interface + * + */ + // The PowerAdjustEnd event needs to report the approximate energy used by the ESA during the session. + int64_t GetApproxEnergyDuringSession() override; + CHIP_ERROR HandleDeviceEnergyManagementPowerAdjustRequest(const int64_t powerMw, const uint32_t durationS, + AdjustmentCauseEnum cause) override; + CHIP_ERROR HandleDeviceEnergyManagementPowerAdjustCompletion() override; + CHIP_ERROR HandleDeviceEnergyManagementCancelPowerAdjustRequest(CauseEnum cause) override; + CHIP_ERROR HandleDeviceEnergyManagementStartTimeAdjustRequest(const uint32_t requestedStartTime, + AdjustmentCauseEnum cause) override; + CHIP_ERROR HandleDeviceEnergyManagementPauseRequest(const uint32_t durationS, AdjustmentCauseEnum cause) override; + CHIP_ERROR HandleDeviceEnergyManagementPauseCompletion() override; + CHIP_ERROR HandleDeviceEnergyManagementCancelPauseRequest(CauseEnum cause) override; + CHIP_ERROR HandleDeviceEnergyManagementCancelRequest() override; + CHIP_ERROR HandleModifyForecastRequest( + const uint32_t forecastID, + const DataModel::DecodableList & slotAdjustments, + AdjustmentCauseEnum cause) override; + CHIP_ERROR RequestConstraintBasedForecast( + const DataModel::DecodableList & constraints, + AdjustmentCauseEnum cause) override; + /** * @brief Called at start up to apply hardware settings */ @@ -172,6 +211,7 @@ class EVSEManufacturer EnergyEvseManager * mEvseInstance; ElectricalPowerMeasurement::ElectricalPowerMeasurementInstance * mEPMInstance; PowerTopology::PowerTopologyInstance * mPTInstance; + DeviceEnergyManagementManager * mDEMInstance; int64_t mLastChargingEnergyMeter = 0; int64_t mLastDischargingEnergyMeter = 0; diff --git a/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h index df0d08b76f7e4e..aed42fa857968a 100644 --- a/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h +++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,13 +26,6 @@ using chip::Protocols::InteractionModel::Status; -/** - * @brief Helper function to get current timestamp in Epoch format - * - * @param chipEpoch reference to hold return timestamp - */ -CHIP_ERROR GetEpochTS(uint32_t & chipEpoch); - namespace chip { namespace app { namespace Clusters { diff --git a/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h b/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h index fc0d41b9259643..f39b0c0c5dd34a 100644 --- a/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h +++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/energy-management-app/energy-management-common/include/EnergyManagementAppCmdLineOptions.h b/examples/energy-management-app/energy-management-common/include/EnergyManagementAppCmdLineOptions.h new file mode 100644 index 00000000000000..a44140b94c762b --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/EnergyManagementAppCmdLineOptions.h @@ -0,0 +1,34 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +chip::BitMask GetFeatureMapFromCmdLine(); + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/EnergyTimeUtils.h b/examples/energy-management-app/energy-management-common/include/EnergyTimeUtils.h new file mode 100644 index 00000000000000..5e882063ad7540 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/EnergyTimeUtils.h @@ -0,0 +1,74 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +/** + * @brief Helper function to get current timestamp in Epoch format + * + * @param chipEpoch reference to hold return timestamp + */ +CHIP_ERROR GetEpochTS(uint32_t & chipEpoch); + +/** + * @brief Helper function to get current timestamp and work out the day of week + * + * NOTE that the time_t is converted using localtime to provide the timestamp + * in local time. If this is not supported on some platforms an alternative + * implementation may be required. + * + * @param unixEpoch (as time_t) + * + * @return bitmap value for day of week as defined by EnergyEvse::TargetDayOfWeekBitmap. Note + * only one bit will be set for the day of the week. + */ +BitMask GetLocalDayOfWeekFromUnixEpoch(time_t unixEpoch); + +/** + * @brief Helper function to get current timestamp and work out the day of week based on localtime + * + * @param reference to hold the day of week as a bitmap as defined by EnergyEvse::TargetDayOfWeekBitmap. + * Note only one bit will be set for the current day. + */ +CHIP_ERROR GetLocalDayOfWeekNow(BitMask & dayOfWeekMap); + +/** + * @brief Helper function to get current timestamp and work out the current number of minutes + * past midnight based on localtime + * + * @param reference to hold the number of minutes past midnight + */ +CHIP_ERROR GetMinutesPastMidnight(uint16_t & minutesPastMidnight); + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/FakeReadings.h b/examples/energy-management-app/energy-management-common/include/FakeReadings.h new file mode 100644 index 00000000000000..f8334ba2708b7e --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/FakeReadings.h @@ -0,0 +1,115 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include + +class FakeReadings +{ +public: + static FakeReadings & GetInstance(); + + /** + * @brief Starts a fake load/generator to periodically callback the power and energy + * clusters. + * @param[in] aEndpointId - which endpoint is the meter to be updated on + * @param[in] aPower_mW - the mean power of the load + * Positive power indicates Imported energy (e.g. a load) + * Negative power indicated Exported energy (e.g. a generator) + * @param[in] aPowerRandomness_mW This is used to define the max randomness of the + * random power values around the mean power of the load + * @param[in] aVoltage_mV - the nominal voltage measurement + * @param[in] aVoltageRandomness_mV This is used to define the max randomness of the + * random voltage values + * @param[in] aCurrent_mA - the nominal current measurement + * @param[in] aCurrentRandomness_mA This is used to define the max randomness of the + * random current values + * @param[in] aInterval_s - the callback interval in seconds + * @param[in] aReset - boolean: true will reset the energy values to 0 + */ + void StartFakeReadings(chip::EndpointId aEndpointId, int64_t aPower_mW, uint32_t aPowerRandomness_mW, int64_t aVoltage_mV, + uint32_t aVoltageRandomness_mV, int64_t aCurrent_mA, uint32_t aCurrentRandomness_mA, uint8_t aInterval_s, + bool aReset); + + /** + * @brief Stops any active updates to the fake load data callbacks + */ + void StopFakeReadings(); + + /** + * @brief Sends fake meter data into the cluster and restarts the timer + */ + void FakeReadingsUpdate(); + + /** + * @brief Timer expiry callback to handle fake load + */ + static void FakeReadingsTimerExpiry(chip::System::Layer * systemLayer, void * manufacturer); + + CHIP_ERROR ConfigureForecast(uint16_t numSlots); + +private: + FakeReadings(); + ~FakeReadings(); + +private: + /* If enabled then the timer callback will re-trigger */ + bool bEnabled; + + /* Which endpoint the meter is on */ + chip::EndpointId mEndpointId; + + /* Interval in seconds to callback */ + uint8_t mInterval_s; + + /* Active Power on the load in mW (signed value) +ve = imported */ + int64_t mPower_mW; + + /* The amount to randomize the Power on the load in mW */ + uint32_t mPowerRandomness_mW; + + /* Voltage reading in mV (signed value) */ + int64_t mVoltage_mV; + + /* The amount to randomize the Voltage in mV */ + uint32_t mVoltageRandomness_mV; + + /* ActiveCurrent reading in mA (signed value) */ + int64_t mCurrent_mA; + + /* The amount to randomize the ActiveCurrent in mA */ + uint32_t mCurrentRandomness_mA; + + /* These energy values can only be positive values. However the underlying + * energy type (power_mWh) is signed, so keeping with that convention. + */ + + /* Cumulative Energy Imported which is updated if mPower > 0 */ + int64_t mTotalEnergyImported = 0; + + /* Cumulative Energy Imported which is updated if mPower < 0 */ + int64_t mTotalEnergyExported = 0; + + /* Periodic Energy Imported which is updated if mPower > 0 */ + int64_t mPeriodicEnergyImported = 0; + + /* Periodic Energy Imported which is updated if mPower < 0 */ + int64_t mPeriodicEnergyExported = 0; +}; diff --git a/examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp b/examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp new file mode 100644 index 00000000000000..469b781a9b6211 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp @@ -0,0 +1,386 @@ +/* + * + * 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 +#include +#include + +#include + +#include "FakeReadings.h" + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; + +static constexpr uint16_t MAX_SLOTS = 10; +static constexpr uint16_t MAX_POWER_ADJUSTMENTS = 5; + +static chip::app::Clusters::DeviceEnergyManagement::Structs::SlotStruct::Type sSlots[MAX_SLOTS]; +static chip::app::Clusters::DeviceEnergyManagement::Structs::ForecastStruct::Type sForecastStruct; +static chip::app::DataModel::Nullable sForecast; + +static chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustStruct::Type sPowerAdjustments[MAX_POWER_ADJUSTMENTS]; +static chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustCapabilityStruct::Type sPowerAdjustCapabilityStruct; +static chip::app::DataModel::Nullable + sPowerAdjustmentCapability; + +DeviceEnergyManagementDelegate * GetDEMDelegate() +{ + EVSEManufacturer * mn = GetEvseManufacturer(); + VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); + DeviceEnergyManagementDelegate * dg = mn->GetDEMDelegate(); + VerifyOrDieWithMsg(dg != nullptr, AppServer, "DEM Delegate is null"); + + return dg; +} + +CHIP_ERROR ConfigureForecast(uint16_t numSlots) +{ + uint32_t chipEpoch = 0; + + CHIP_ERROR err = GetEpochTS(chipEpoch); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Support, "ConfigureForecast could not get time"); + return err; + } + + // planned start time, in UTC, for the entire Forecast. Allow to be a little + // time in the future as forecastStruct.startTime is used in some tests. + sForecastStruct.startTime = chipEpoch + 60; + + // earliest start time, in UTC, that the entire Forecast can be shifted to. null value indicates that it can be started + // immediately. + sForecastStruct.earliestStartTime = MakeOptional(DataModel::MakeNullable(chipEpoch)); + + // planned end time, in UTC, for the entire Forecast. + sForecastStruct.endTime = chipEpoch * 3; + + // latest end time, in UTC, for the entire Forecast + sForecastStruct.latestEndTime = MakeOptional(chipEpoch * 3); + + sForecastStruct.isPausable = true; + + sForecastStruct.activeSlotNumber.SetNonNull(0); + + sSlots[0].minDuration = 10; + sSlots[0].maxDuration = 20; + sSlots[0].defaultDuration = 15; + sSlots[0].elapsedSlotTime = 0; + sSlots[0].remainingSlotTime = 0; + + sSlots[0].slotIsPausable.SetValue(true); + sSlots[0].minPauseDuration.SetValue(10); + sSlots[0].maxPauseDuration.SetValue(60); + + if (GetDEMDelegate()->HasFeature(DeviceEnergyManagement::Feature::kPowerForecastReporting)) + { + sSlots[0].nominalPower.SetValue(1500); + sSlots[0].minPower.SetValue(1000); + sSlots[0].maxPower.SetValue(2000); + } + + sSlots[0].nominalEnergy.SetValue(2000); + + if (GetDEMDelegate()->HasFeature(DeviceEnergyManagement::Feature::kStateForecastReporting)) + { + sSlots[0].manufacturerESAState.SetValue(23); + } + + for (uint16_t slotNo = 1; slotNo < numSlots; slotNo++) + { + sSlots[slotNo].minDuration = 2 * sSlots[slotNo - 1].minDuration; + sSlots[slotNo].maxDuration = 2 * sSlots[slotNo - 1].maxDuration; + sSlots[slotNo].defaultDuration = 2 * sSlots[slotNo - 1].defaultDuration; + sSlots[slotNo].elapsedSlotTime = 2 * sSlots[slotNo - 1].elapsedSlotTime; + sSlots[slotNo].remainingSlotTime = 2 * sSlots[slotNo - 1].remainingSlotTime; + + // Need slotNo == 1 not to be pausible for test DEM 2.4 step 3b + sSlots[slotNo].slotIsPausable.SetValue((slotNo & 1) == 0 ? true : false); + sSlots[slotNo].minPauseDuration.SetValue(2 * sSlots[slotNo - 1].slotIsPausable.Value()); + sSlots[slotNo].maxPauseDuration.SetValue(2 * sSlots[slotNo - 1].maxPauseDuration.Value()); + + if (GetDEMDelegate()->HasFeature(DeviceEnergyManagement::Feature::kPowerForecastReporting)) + { + sSlots[slotNo].nominalPower.SetValue(2 * sSlots[slotNo - 1].nominalPower.Value()); + sSlots[slotNo].minPower.SetValue(2 * sSlots[slotNo - 1].minPower.Value()); + sSlots[slotNo].maxPower.SetValue(2 * sSlots[slotNo - 1].maxPower.Value()); + + sSlots[slotNo].nominalEnergy.SetValue(2 * sSlots[slotNo - 1].nominalEnergy.Value()); + } + + if (GetDEMDelegate()->HasFeature(DeviceEnergyManagement::Feature::kStateForecastReporting)) + { + sSlots[slotNo].manufacturerESAState.SetValue(sSlots[slotNo - 1].manufacturerESAState.Value() + 1); + } + } + + sForecastStruct.slots = DataModel::List(sSlots, numSlots); + + EVSEManufacturer * mn = GetEvseManufacturer(); + mn->GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); + mn->GetDEMDelegate()->SetAbsMinPower(1000); + mn->GetDEMDelegate()->SetAbsMaxPower(256 * 2000 * 1000); + + return CHIP_NO_ERROR; +} + +void SetTestEventTrigger_PowerAdjustment() +{ + sPowerAdjustments[0].minPower = 5000 * 1000; // 5kW + sPowerAdjustments[0].maxPower = 30000 * 1000; // 30kW + sPowerAdjustments[0].minDuration = 10; // 30s + sPowerAdjustments[0].maxDuration = 60; // 60s + + DataModel::List powerAdjustmentList(sPowerAdjustments, 1); + + sPowerAdjustCapabilityStruct.cause = PowerAdjustReasonEnum::kNoAdjustment; + sPowerAdjustCapabilityStruct.powerAdjustCapability.SetNonNull(powerAdjustmentList); + sPowerAdjustmentCapability.SetNonNull(sPowerAdjustCapabilityStruct); + + CHIP_ERROR err = GetDEMDelegate()->SetPowerAdjustmentCapability(sPowerAdjustmentCapability); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Support, "SetTestEventTrigger_PowerAdjustment failed %s", chip::ErrorStr(err)); + } +} + +void SetTestEventTrigger_ClearForecast() +{ + sPowerAdjustments[0].minPower = 0; + sPowerAdjustments[0].maxPower = 0; + sPowerAdjustments[0].minDuration = 0; + sPowerAdjustments[0].maxDuration = 0; + + DataModel::List powerAdjustmentList(sPowerAdjustments, 1); + + sPowerAdjustCapabilityStruct.powerAdjustCapability.SetNonNull(powerAdjustmentList); + sPowerAdjustCapabilityStruct.cause = PowerAdjustReasonEnum::kNoAdjustment; + + DataModel::Nullable powerAdjustmentCapabilityStruct( + sPowerAdjustCapabilityStruct); + + CHIP_ERROR err = GetDEMDelegate()->SetPowerAdjustmentCapability(powerAdjustmentCapabilityStruct); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Support, "SetTestEventTrigger_PowerAdjustment failed %s", chip::ErrorStr(err)); + } +} + +void SetTestEventTrigger_StartTimeAdjustment() +{ + ConfigureForecast(2); + + // Get the current forecast ad update the earliestStartTime and latestEndTime + sForecastStruct = GetDEMDelegate()->GetForecast().Value(); + + uint32_t chipEpoch = 0; + + CHIP_ERROR err = GetEpochTS(chipEpoch); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Support, "ConfigureForecast_EarliestStartLatestEndTimes could not get time"); + } + + // planned start time, in UTC, for the entire Forecast. + sForecastStruct.startTime = chipEpoch; + + // Set the earliest start time, in UTC, to that before the startTime + sForecastStruct.earliestStartTime = Optional>{ DataModel::Nullable{ chipEpoch - 60 } }; + + // Planned end time, in UTC, for the entire Forecast. + sForecastStruct.endTime = chipEpoch * 3; + + // Latest end time, in UTC, for the entire Forecast which is > sForecastStruct.endTime + sForecastStruct.latestEndTime = Optional(chipEpoch * 3 + 60); + + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); +} + +void SetTestEventTrigger_StartTimeAdjustmentClear() +{ + // Get the current forecast ad update the earliestStartTime and latestEndTime + sForecastStruct = GetDEMDelegate()->GetForecast().Value(); + + sForecastStruct.startTime = static_cast(0); + sForecastStruct.endTime = static_cast(0); + + sForecastStruct.earliestStartTime = NullOptional; + sForecastStruct.latestEndTime = NullOptional; + + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); +} + +void SetTestEventTrigger_UserOptOutOptimization(OptOutStateEnum optOutState) +{ + GetDEMDelegate()->SetOptOutState(optOutState); +} + +void SetTestEventTrigger_Pausable() +{ + ConfigureForecast(2); +} + +void SetTestEventTrigger_PausableNextSlot() +{ + // Get the current forecast ad update the active slot number + sForecastStruct = GetDEMDelegate()->GetForecast().Value(); + sForecastStruct.activeSlotNumber.SetNonNull(1); + + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); +} + +void SetTestEventTrigger_Forecast() +{ + ConfigureForecast(2); +} + +void SetTestEventTrigger_ForecastClear() +{ + sForecastStruct.startTime = 0; + sForecastStruct.endTime = 0; + sForecastStruct.earliestStartTime.ClearValue(); + sForecastStruct.latestEndTime.ClearValue(); + sForecastStruct.isPausable = false; + sForecastStruct.activeSlotNumber.SetNull(); + sForecastStruct.slots = DataModel::List(); + + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); +} + +void SetTestEventTrigger_ForecastAdjustment() +{ + ConfigureForecast(2); + + // The following values need to match the equivalent values in src/python_testing/TC_DEM_2_5.py + sForecastStruct = GetDEMDelegate()->GetForecast().Value(); + sSlots[0].minPowerAdjustment.SetValue(20); + sSlots[0].maxPowerAdjustment.SetValue(2000); + sSlots[0].minDurationAdjustment.SetValue(120); + sSlots[0].maxDurationAdjustment.SetValue(240); + + sForecastStruct.slots = DataModel::List(sSlots, 2); + + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); +} + +void SetTestEventTrigger_ForecastAdjustmentNextSlot() +{ + sForecastStruct = GetDEMDelegate()->GetForecast().Value(); + sForecastStruct.activeSlotNumber.SetNonNull(sForecastStruct.activeSlotNumber.Value() + 1); + + GetDEMDelegate()->SetForecast(DataModel::MakeNullable(sForecastStruct)); +} + +void SetTestEventTrigger_ConstraintBasedAdjustment() +{ + ConfigureForecast(4); +} + +bool HandleDeviceEnergyManagementTestEventTrigger(uint64_t eventTrigger) +{ + DeviceEnergyManagementTrigger trigger = static_cast(eventTrigger); + + switch (trigger) + { + case DeviceEnergyManagementTrigger::kPowerAdjustment: + ChipLogProgress( + Support, + "[PowerAdjustment-Test-Event] => Simulate a fixed forecast power usage including one or more PowerAdjustmentStructs"); + SetTestEventTrigger_PowerAdjustment(); + break; + case DeviceEnergyManagementTrigger::kPowerAdjustmentClear: + ChipLogProgress(Support, "[PowerAdjustmentClear-Test-Event] => Clear the PowerAdjustment structs"); + SetTestEventTrigger_ClearForecast(); + break; + case DeviceEnergyManagementTrigger::kUserOptOutLocalOptimization: + ChipLogProgress(Support, "[UserOptOutLocalOptimization-Test-Event] => Simulate user opt-out of Local Optimization"); + SetTestEventTrigger_UserOptOutOptimization(OptOutStateEnum::kLocalOptOut); + break; + case DeviceEnergyManagementTrigger::kUserOptOutGridOptimization: + ChipLogProgress(Support, "[UserOptOutGrisOptimization-Test-Event] => Simulate user opt-out of Grid Optimization"); + SetTestEventTrigger_UserOptOutOptimization(OptOutStateEnum::kGridOptOut); + break; + case DeviceEnergyManagementTrigger::kUserOptOutClearAll: + ChipLogProgress(Support, "[UserOptOutClearAll-Test-Event] => Remove all user opt-out opting out"); + SetTestEventTrigger_UserOptOutOptimization(OptOutStateEnum::kNoOptOut); + break; + case DeviceEnergyManagementTrigger::kStartTimeAdjustment: + ChipLogProgress(Support, + "[StartTimeAdjustment-Test-Event] => Simulate a fixed forecast with EarliestStartTime earlier than " + "startTime, and LatestEndTime greater than EndTime"); + SetTestEventTrigger_StartTimeAdjustment(); + break; + case DeviceEnergyManagementTrigger::kStartTimeAdjustmentClear: + ChipLogProgress(Support, "[StartTimeAdjustmentClear-Test-Event] => Clear the StartTimeAdjustment simulated forecast"); + SetTestEventTrigger_StartTimeAdjustmentClear(); + break; + case DeviceEnergyManagementTrigger::kPausable: + ChipLogProgress(Support, + "[Pausable-Test-Event] => Simulate a fixed forecast with one pausable slot with MinPauseDuration >1, " + "MaxPauseDuration>1 and one non pausable slot"); + SetTestEventTrigger_Pausable(); + break; + case DeviceEnergyManagementTrigger::kPausableNextSlot: + ChipLogProgress(Support, "[PausableNextSlot-Test-Event] => Simulate a moving time to the next forecast slot"); + SetTestEventTrigger_PausableNextSlot(); + break; + case DeviceEnergyManagementTrigger::kPausableClear: + ChipLogProgress(Support, "[PausableClear-Test-Event] => Clear the Pausable simulated forecast"); + SetTestEventTrigger_ClearForecast(); + break; + case DeviceEnergyManagementTrigger::kForecastAdjustment: + ChipLogProgress(Support, + "[ForecastAdjustment-Test-Event] => Simulate a forecast power usage with at least 2 and at most 4 slots"); + SetTestEventTrigger_ForecastAdjustment(); + break; + case DeviceEnergyManagementTrigger::kForecastAdjustmentNextSlot: + ChipLogProgress(Support, "[ForecastAdjustmentNextSlot-Test-Event] => Simulate moving time to the next forecast slot"); + SetTestEventTrigger_ForecastAdjustmentNextSlot(); + break; + case DeviceEnergyManagementTrigger::kForecastAdjustmentClear: + ChipLogProgress(Support, "[ForecastAdjustmentClear-Test-Event] => Clear the forecast adjustment"); + SetTestEventTrigger_ClearForecast(); + break; + case DeviceEnergyManagementTrigger::kConstraintBasedAdjustment: + ChipLogProgress( + Support, + "[ConstraintBasedAdjustment-Test-Event] => Simulate a forecast power usage with at least 2 and at most 4 slots"); + SetTestEventTrigger_ConstraintBasedAdjustment(); + break; + case DeviceEnergyManagementTrigger::kConstraintBasedAdjustmentClear: + ChipLogProgress(Support, "[ConstraintBasedAdjustmentClear-Test-Event] => Clear the constraint based adjustment"); + SetTestEventTrigger_ClearForecast(); + break; + case DeviceEnergyManagementTrigger::kForecast: + ChipLogProgress(Support, "[Forecast-Test-Event] => Create a forecast with at least 1 slot"); + SetTestEventTrigger_Forecast(); + break; + case DeviceEnergyManagementTrigger::kForecastClear: + ChipLogProgress(Support, "[ForecastClear-Test-Event] => Clear the forecast"); + SetTestEventTrigger_ForecastClear(); + break; + + default: + return false; + } + + return true; +} diff --git a/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp index 8f122bdac2b046..273bc9e0614333 100644 --- a/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp +++ b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,8 +17,10 @@ */ #include "DeviceEnergyManagementDelegateImpl.h" - +#include "DEMManufacturerDelegate.h" +#include "EnergyTimeUtils.h" #include +#include using namespace chip; using namespace chip::app; @@ -26,10 +28,40 @@ using namespace chip::app::Clusters; using namespace chip::app::Clusters::DeviceEnergyManagement; using namespace chip::app::Clusters::DeviceEnergyManagement::Attributes; +using chip::Protocols::InteractionModel::Status; + using chip::Optional; -using namespace chip::app; using CostsList = DataModel::List; +DeviceEnergyManagementDelegate::DeviceEnergyManagementDelegate() : + mpDEMManufacturerDelegate(nullptr), mEsaType(ESATypeEnum::kEvse), mEsaCanGenerate(false), mEsaState(ESAStateEnum::kOffline), + mAbsMinPowerMw(0), mAbsMaxPowerMw(0), mOptOutState(OptOutStateEnum::kNoOptOut), mPowerAdjustmentInProgress(false), + mPowerAdjustmentStartTimeUtc(0), mPauseRequestInProgress(false) +{} + +void DeviceEnergyManagementDelegate::SetDeviceEnergyManagementInstance(DeviceEnergyManagement::Instance & instance) +{ + mpDEMInstance = &instance; +} + +uint32_t DeviceEnergyManagementDelegate::HasFeature(Feature feature) const +{ + bool hasFeature = false; + + if (mpDEMInstance != nullptr) + { + hasFeature = mpDEMInstance->HasFeature(feature); + } + + return hasFeature; +} + +void DeviceEnergyManagementDelegate::SetDEMManufacturerDelegate( + DEMManufacturerDelegate & deviceEnergyManagementManufacturerDelegate) +{ + mpDEMManufacturerDelegate = &deviceEnergyManagementManufacturerDelegate; +} + /** * @brief Delegate handler for PowerAdjustRequest * @@ -47,27 +79,156 @@ using CostsList = DataModel::List; * 6) generate a PowerAdjustEnd event with cause NormalCompletion * 7) if necessary, update the forecast with new expected end time */ -Status DeviceEnergyManagementDelegate::PowerAdjustRequest(const int64_t power, const uint32_t duration, AdjustmentCauseEnum cause) +Status DeviceEnergyManagementDelegate::PowerAdjustRequest(const int64_t powerMw, const uint32_t durationS, + AdjustmentCauseEnum cause) { - Status status = Status::UnsupportedCommand; // Status::Success; + bool generateEvent = false; - // TODO: implement - mEsaState = ESAStateEnum::kPowerAdjustActive; + // If a timer is running, cancel it so we can start it with the new duration + if (mPowerAdjustmentInProgress) + { + DeviceLayer::SystemLayer().CancelTimer(PowerAdjustTimerExpiry, this); + } + else + { + // Going to start a new power adjustment so will need to generate an event + generateEvent = true; + + // Record when this PowerAdjustment starts. Note if we do not set this value if a PowerAdjustment is in progress + CHIP_ERROR err = GetEpochTS(mPowerAdjustmentStartTimeUtc); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Unable to get time: %" CHIP_ERROR_FORMAT, err.Format()); + return Status::Failure; + } + } - // TODO: Generate a PowerAdjustStart Event, then begins to adjust its power - // When done, raise PowerAdjustEnd & ESAState set to kOnline. + // Update the forecast with the new expected end time + if (mpDEMManufacturerDelegate != nullptr) + { + CHIP_ERROR err = mpDEMManufacturerDelegate->HandleDeviceEnergyManagementPowerAdjustRequest(powerMw, durationS, cause); + if (err != CHIP_NO_ERROR) + { + return Status::Failure; + } + } - MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESAState::Id); + SetESAState(ESAStateEnum::kPowerAdjustActive); - return status; + // mPowerAdjustCapabilityStruct is guaranteed to have a value as validated in Instance::HandlePowerAdjustRequest. + // If it did not have a value, this method would not have been called. + switch (cause) + { + case AdjustmentCauseEnum::kLocalOptimization: + mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kLocalOptimizationAdjustment; + break; + + case AdjustmentCauseEnum::kGridOptimization: + mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kGridOptimizationAdjustment; + break; + + default: + HandlePowerAdjustRequestFailure(); + return Status::Failure; + } + + // Remember we have a timer running so we don't generate a PowerAdjustStart event should another request come + // in before this timer expires + mPowerAdjustmentInProgress = true; + + CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(durationS), PowerAdjustTimerExpiry, this); + if (err != CHIP_NO_ERROR) + { + // TODO: Note: should the PowerAdjust just initiated be cancelled because an Event could not be logged? + ChipLogError(AppServer, "Unable to start a PowerAdjustStart timer: %" CHIP_ERROR_FORMAT, err.Format()); + HandlePowerAdjustRequestFailure(); + return Status::Failure; + } + + if (generateEvent) + { + Events::PowerAdjustStart::Type event; + EventNumber eventNumber; + err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + // TODO: Note: should the PowerAdjust just initiated be cancelled because an Event could not be logged? + ChipLogError(AppServer, "Unable to generate PowerAdjustStart event: %" CHIP_ERROR_FORMAT, err.Format()); + HandlePowerAdjustRequestFailure(); + return Status::Failure; + } + } + + return Status::Success; +} + +/** + * @brief Handle a PowerAdjustRequest failing + * + * Cleans up the PowerAdjust state should the request fail + */ +void DeviceEnergyManagementDelegate::HandlePowerAdjustRequestFailure() +{ + DeviceLayer::SystemLayer().CancelTimer(PowerAdjustTimerExpiry, this); + + SetESAState(ESAStateEnum::kOnline); + + mPowerAdjustmentInProgress = false; + + mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kNoAdjustment; + + // TODO + // Should we inform the mpDEMManufacturerDelegate that PowerAdjustRequest has failed? } + +/** + * @brief Timer for handling the PowerAdjustRequest + * + * This static function calls the non-static HandlePowerAdjustTimerExpiry method. + */ +void DeviceEnergyManagementDelegate::PowerAdjustTimerExpiry(System::Layer * systemLayer, void * delegate) +{ + DeviceEnergyManagementDelegate * dg = reinterpret_cast(delegate); + + dg->HandlePowerAdjustTimerExpiry(); +} + +/** + * @brief Timer for handling the completion of a PowerAdjustRequest + * + * When the timer expires: + * 1) notify the appliance's that it can resume its intended power setting (or go idle) + * 2) generate a PowerAdjustEnd event with cause NormalCompletion + * 3) if necessary, update the forecast with new expected end time + */ +void DeviceEnergyManagementDelegate::HandlePowerAdjustTimerExpiry() +{ + ChipLogError(AppServer, "DeviceEnergyManagementDelegate::HandlePowerAdjustTimerExpiry"); + + // The PowerAdjustment is no longer in progress + mPowerAdjustmentInProgress = false; + + SetESAState(ESAStateEnum::kOnline); + + mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kNoAdjustment; + + // Generate a PowerAdjustEnd event + GeneratePowerAdjustEndEvent(CauseEnum::kNormalCompletion); + + // Update the forecast with new expected end time + if (mpDEMManufacturerDelegate != nullptr) + { + mpDEMManufacturerDelegate->HandleDeviceEnergyManagementPowerAdjustCompletion(); + } +} + /** * @brief Delegate handler for CancelPowerAdjustRequest * * Note: checking of the validity of the CancelPowerAdjustRequest has been done by the lower layer * * This function needs to notify the appliance that it should resume its intended power setting (or go idle). - + * * It should: * 1) notify the appliance's that it can resume its intended power setting (or go idle) * 2) generate a PowerAdjustEnd event with cause code Cancelled @@ -75,16 +236,91 @@ Status DeviceEnergyManagementDelegate::PowerAdjustRequest(const int64_t power, c */ Status DeviceEnergyManagementDelegate::CancelPowerAdjustRequest() { - Status status = Status::UnsupportedCommand; // Status::Success; + Status status = Status::Success; - // TODO: implement - /* TODO: If the command is accepted, the ESA SHALL generate an PowerAdjustEnd Event. */ - mEsaState = ESAStateEnum::kOnline; - MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, ESAState::Id); + CHIP_ERROR err = CancelPowerAdjustRequestAndGenerateEvent(DeviceEnergyManagement::CauseEnum::kCancelled); + if (CHIP_NO_ERROR != err) + { + status = Status::Failure; + } return status; } +/** + * @brief Handles the cancelation of a PowerAdjust operation + * + * This function needs to notify the appliance that it should resume its intended power setting (or go idle). + * + * It should: + * 1) notify the appliance's that it can resume its intended power setting (or go idle) + * 2) generate a PowerAdjustEnd event with cause code Cancelled + * 3) if necessary, update the forecast with new expected end time + */ +CHIP_ERROR DeviceEnergyManagementDelegate::CancelPowerAdjustRequestAndGenerateEvent(CauseEnum cause) +{ + DeviceLayer::SystemLayer().CancelTimer(PowerAdjustTimerExpiry, this); + + SetESAState(ESAStateEnum::kOnline); + + mPowerAdjustmentInProgress = false; + + mPowerAdjustCapabilityStruct.Value().cause = PowerAdjustReasonEnum::kNoAdjustment; + + CHIP_ERROR err = GeneratePowerAdjustEndEvent(cause); + + // Notify the appliance's that it can resume its intended power setting (or go idle) + if (mpDEMManufacturerDelegate != nullptr) + { + // It is expected the mpDEMManufacturerDelegate will update the forecast with new expected end time + // as a consequence of the cancel request. + err = mpDEMManufacturerDelegate->HandleDeviceEnergyManagementCancelPowerAdjustRequest(cause); + } + + return err; +} + +/** + * @brief Generate a PowerAdjustEvent + * + */ +CHIP_ERROR DeviceEnergyManagementDelegate::GeneratePowerAdjustEndEvent(CauseEnum cause) +{ + Events::PowerAdjustEnd::Type event; + EventNumber eventNumber; + event.cause = cause; + + uint32_t timeNowUtc; + CHIP_ERROR err = GetEpochTS(timeNowUtc); + if (err == CHIP_NO_ERROR) + { + event.duration = timeNowUtc - mPowerAdjustmentStartTimeUtc; + } + else + { + ChipLogError(AppServer, "Unable to get time: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + if (mpDEMManufacturerDelegate != nullptr) + { + event.energyUse = mpDEMManufacturerDelegate->GetApproxEnergyDuringSession(); + } + else + { + event.energyUse = 0; + } + + err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Unable to generate PowerAdjustEnd event: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + return err; +} + /** * @brief Delegate handler for StartTimeAdjustRequest * @@ -96,27 +332,58 @@ Status DeviceEnergyManagementDelegate::CancelPowerAdjustRequest() * 1) update the forecast attribute with the revised start time * 2) send a callback notification to the appliance so it can refresh its internal schedule */ -Status DeviceEnergyManagementDelegate::StartTimeAdjustRequest(const uint32_t requestedStartTime, AdjustmentCauseEnum cause) +Status DeviceEnergyManagementDelegate::StartTimeAdjustRequest(const uint32_t requestedStartTimeUtc, AdjustmentCauseEnum cause) { - DataModel::Nullable forecast = GetForecast(); + if (mForecast.IsNull()) + { + return Status::Failure; + } - if (forecast.IsNull()) + switch (cause) { + case AdjustmentCauseEnum::kLocalOptimization: + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kLocalOptimization; + break; + case AdjustmentCauseEnum::kGridOptimization: + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kGridOptimization; + break; + default: + ChipLogDetail(AppServer, "Bad cause %d", to_underlying(cause)); return Status::Failure; + break; } - uint32_t duration = forecast.Value().endTime - forecast.Value().startTime; // the current entire forecast duration + mForecast.Value().forecastID++; - /* Modify start time and end time */ - forecast.Value().startTime = requestedStartTime; - forecast.Value().endTime = requestedStartTime + duration; + uint32_t durationS = mForecast.Value().endTime - mForecast.Value().startTime; // the current entire forecast duration + + // Save the start and end time in case there is an issue with the mpDEMManufacturerDelegate handling this + // startTimeAdjustment request + uint32_t savedStartTime = mForecast.Value().startTime; + uint32_t savedEndTime = mForecast.Value().endTime; - SetForecast(forecast); // This will increment forecast ID + /* Modify start time and end time */ + mForecast.Value().startTime = requestedStartTimeUtc; + mForecast.Value().endTime = requestedStartTimeUtc + durationS; - // TODO: callback to the appliance to notify it of a new start time + if (mpDEMManufacturerDelegate != nullptr) + { + CHIP_ERROR err = + mpDEMManufacturerDelegate->HandleDeviceEnergyManagementStartTimeAdjustRequest(requestedStartTimeUtc, cause); + if (err != CHIP_NO_ERROR) + { + // Reset state + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + mForecast.Value().startTime = savedStartTime; + mForecast.Value().endTime = savedEndTime; + + return Status::Failure; + } + } return Status::Success; } + /** * @brief Delegate handler for Pause Request * @@ -134,11 +401,184 @@ Status DeviceEnergyManagementDelegate::StartTimeAdjustRequest(const uint32_t req * 6) generate a Resumed event * 7) if necessary, update the forecast with new expected end time */ -Status DeviceEnergyManagementDelegate::PauseRequest(const uint32_t duration, AdjustmentCauseEnum cause) +Status DeviceEnergyManagementDelegate::PauseRequest(const uint32_t durationS, AdjustmentCauseEnum cause) { - Status status = Status::UnsupportedCommand; // Status::Success; - // TODO: implement the behaviour above - return status; + bool generateEvent = false; + + // If a timer is running, cancel it so we can start it with the new duration + if (mPauseRequestInProgress) + { + DeviceLayer::SystemLayer().CancelTimer(PauseRequestTimerExpiry, this); + } + else + { + generateEvent = true; + + // Remember we have a timer running so we don't generate a Paused event should another request come + // in before this timer expires + mPauseRequestInProgress = true; + } + + CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(durationS), PauseRequestTimerExpiry, this); + if (err != CHIP_NO_ERROR) + { + HandlePauseRequestFailure(); + return Status::Failure; + } + + // Pause the appliance + if (mpDEMManufacturerDelegate != nullptr) + { + // It is expected that the mpDEMManufacturerDelegate will update the forecast with the new expected end time + err = mpDEMManufacturerDelegate->HandleDeviceEnergyManagementPauseRequest(durationS, cause); + if (err != CHIP_NO_ERROR) + { + HandlePauseRequestFailure(); + return Status::Failure; + } + } + + if (generateEvent) + { + Events::Paused::Type event; + EventNumber eventNumber; + err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Unable to generate Paused event: %" CHIP_ERROR_FORMAT, err.Format()); + HandlePauseRequestFailure(); + return Status::Failure; + } + } + + SetESAState(ESAStateEnum::kPaused); + + // Update the forecaseUpdateReason based on the AdjustmentCause + if (cause == AdjustmentCauseEnum::kLocalOptimization) + { + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kLocalOptimization; + } + else if (cause == AdjustmentCauseEnum::kGridOptimization) + { + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kGridOptimization; + } + + return Status::Success; +} + +/** + * @brief Handle a PauseRequest failing + * + * Cleans up the state should the PauseRequest fail + */ +void DeviceEnergyManagementDelegate::HandlePauseRequestFailure() +{ + DeviceLayer::SystemLayer().CancelTimer(PowerAdjustTimerExpiry, this); + + SetESAState(ESAStateEnum::kOnline); + + mPauseRequestInProgress = false; + + // TODO + // Should we inform the mpDEMManufacturerDelegate that PauseRequest has failed? +} + +/** + * @brief Timer for handling the PauseRequest + * + * This static function calls the non-static HandlePauseRequestTimerExpiry method. + */ +void DeviceEnergyManagementDelegate::PauseRequestTimerExpiry(System::Layer * systemLayer, void * delegate) +{ + DeviceEnergyManagementDelegate * dg = reinterpret_cast(delegate); + + dg->HandlePauseRequestTimerExpiry(); +} + +/** + * @brief Timer for handling the completion of a PauseRequest + * + * When the timer expires: + * 1) restore the appliance's operational state + * 2) generate a Resumed event + * 3) if necessary, update the forecast with new expected end time + */ +void DeviceEnergyManagementDelegate::HandlePauseRequestTimerExpiry() +{ + // The PauseRequestment is no longer in progress + mPauseRequestInProgress = false; + + SetESAState(ESAStateEnum::kOnline); + + // Generate a Resumed event + GenerateResumedEvent(CauseEnum::kNormalCompletion); + + // It is expected the mpDEMManufacturerDelegate will update the forecast with new expected end time + if (mpDEMManufacturerDelegate != nullptr) + { + mpDEMManufacturerDelegate->HandleDeviceEnergyManagementPauseCompletion(); + } +} + +/** + * @brief Handles the cancelation of a pause operation + * + * This function needs to notify the appliance that it should resume its intended power setting (or go idle). + * + * It should: + * 1) notify the appliance's that it can resume its intended power setting (or go idle) + * 2) generate a PowerAdjustEnd event with cause code Cancelled + * 3) if necessary, update the forecast with new expected end time + */ +CHIP_ERROR DeviceEnergyManagementDelegate::CancelPauseRequestAndGenerateEvent(CauseEnum cause) +{ + mPauseRequestInProgress = false; + + SetESAState(ESAStateEnum::kOnline); + + DeviceLayer::SystemLayer().CancelTimer(PauseRequestTimerExpiry, this); + + CHIP_ERROR err = GenerateResumedEvent(cause); + CHIP_ERROR err2 = CHIP_NO_ERROR; + + // Notify the appliance's that it can resume its intended power setting (or go idle) + if (mpDEMManufacturerDelegate != nullptr) + { + // It is expected that the mpDEMManufacturerDelegate will update the forecast with new expected end time + err2 = mpDEMManufacturerDelegate->HandleDeviceEnergyManagementCancelPauseRequest(cause); + } + + // Need to pick one of the error codes two return... + if (err == CHIP_NO_ERROR && err2 == CHIP_NO_ERROR) + { + return CHIP_NO_ERROR; + } + + if (err2 != CHIP_NO_ERROR) + { + return err2; + } + + return err; +} + +/** + * @brief Generate a Resumed event + * + */ +CHIP_ERROR DeviceEnergyManagementDelegate::GenerateResumedEvent(CauseEnum cause) +{ + Events::Resumed::Type event; + EventNumber eventNumber; + event.cause = cause; + + CHIP_ERROR err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Unable to generate Resumed event: %" CHIP_ERROR_FORMAT, err.Format()); + } + + return err; } /** @@ -156,10 +596,24 @@ Status DeviceEnergyManagementDelegate::PauseRequest(const uint32_t duration, Adj */ Status DeviceEnergyManagementDelegate::ResumeRequest() { - Status status = Status::UnsupportedCommand; // Status::Success; + Status status = Status::Failure; - // TODO: implement the behaviour above - SetESAState(ESAStateEnum::kOnline); + if (mPauseRequestInProgress) + { + // Guard against mForecast being null + if (!mForecast.IsNull()) + { + // The PauseRequest has effectively been cancelled so as a result the device should + // go back to InternalOptimisation + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + } + + CHIP_ERROR err = CancelPauseRequestAndGenerateEvent(CauseEnum::kCancelled); + if (err == CHIP_NO_ERROR) + { + status = Status::Success; + } + } return status; } @@ -179,12 +633,47 @@ Status DeviceEnergyManagementDelegate::ResumeRequest() * 3) notify the appliance to follow the revised schedule */ Status DeviceEnergyManagementDelegate::ModifyForecastRequest( - const uint32_t forecastId, const DataModel::DecodableList & slotAdjustments, + const uint32_t forecastID, const DataModel::DecodableList & slotAdjustments, AdjustmentCauseEnum cause) { - Status status = Status::UnsupportedCommand; // Status::Success; + Status status = Status::Success; + + if (mForecast.IsNull()) + { + status = Status::Failure; + } + else if (mForecast.Value().forecastID != forecastID) + { + status = Status::Failure; + } + else if (mpDEMManufacturerDelegate != nullptr) + { + // Determine if the new forecast adjustments are acceptable to the appliance + CHIP_ERROR err = mpDEMManufacturerDelegate->HandleModifyForecastRequest(forecastID, slotAdjustments, cause); + if (err != CHIP_NO_ERROR) + { + status = Status::Failure; + } + } + + if (status == Status::Success) + { + switch (cause) + { + case AdjustmentCauseEnum::kLocalOptimization: + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kLocalOptimization; + break; + case AdjustmentCauseEnum::kGridOptimization: + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kGridOptimization; + break; + default: + // Already checked in chip::app::Clusters::DeviceEnergyManagement::Instance::HandleModifyForecastRequest + break; + } + + mForecast.Value().forecastID++; + } - // TODO: implement the behaviour above return status; } @@ -203,8 +692,42 @@ Status DeviceEnergyManagementDelegate::ModifyForecastRequest( Status DeviceEnergyManagementDelegate::RequestConstraintBasedForecast( const DataModel::DecodableList & constraints, AdjustmentCauseEnum cause) { - Status status = Status::UnsupportedCommand; // Status::Success; - // TODO: implement the behaviour above + Status status = Status::Success; + + if (mForecast.IsNull()) + { + status = Status::Failure; + } + else if (mpDEMManufacturerDelegate != nullptr) + { + // Determine if the new forecast adjustments are acceptable to the appliance + CHIP_ERROR err = mpDEMManufacturerDelegate->RequestConstraintBasedForecast(constraints, cause); + if (err != CHIP_NO_ERROR) + { + status = Status::Failure; + } + } + + if (status == Status::Success) + { + switch (cause) + { + case AdjustmentCauseEnum::kLocalOptimization: + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kLocalOptimization; + break; + case AdjustmentCauseEnum::kGridOptimization: + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kGridOptimization; + break; + default: + // Already checked in chip::app::Clusters::DeviceEnergyManagement::Instance::HandleModifyForecastRequest + break; + } + + mForecast.Value().forecastID++; + + status = Status::Success; + } + return status; } @@ -221,8 +744,23 @@ Status DeviceEnergyManagementDelegate::RequestConstraintBasedForecast( */ Status DeviceEnergyManagementDelegate::CancelRequest() { - Status status = Status::UnsupportedCommand; // Status::Success; - // TODO: implement the behaviour above + Status status = Status::Success; + + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + + /* It is expected the mpDEMManufacturerDelegate will cancel the effects of any previous adjustment + * request commands, and re-evaluate its forecast for intended operation ignoring those previous + * requests. + */ + if (mpDEMManufacturerDelegate != nullptr) + { + CHIP_ERROR error = mpDEMManufacturerDelegate->HandleDeviceEnergyManagementCancelRequest(); + if (error != CHIP_NO_ERROR) + { + status = Status::Failure; + } + } + return status; } @@ -245,26 +783,30 @@ ESAStateEnum DeviceEnergyManagementDelegate::GetESAState() int64_t DeviceEnergyManagementDelegate::GetAbsMinPower() { - return mAbsMinPower; + return mAbsMinPowerMw; } int64_t DeviceEnergyManagementDelegate::GetAbsMaxPower() { - return mAbsMaxPower; + return mAbsMaxPowerMw; } -PowerAdjustmentCapability::TypeInfo::Type DeviceEnergyManagementDelegate::GetPowerAdjustmentCapability() +const DataModel::Nullable & +DeviceEnergyManagementDelegate::GetPowerAdjustmentCapability() { - return mPowerAdjustmentCapability; + return mPowerAdjustCapabilityStruct; } -DataModel::Nullable DeviceEnergyManagementDelegate::GetForecast() +const DataModel::Nullable & DeviceEnergyManagementDelegate::GetForecast() { + ChipLogDetail(Zcl, "DeviceEnergyManagementDelegate::GetForecast"); + return mForecast; } OptOutStateEnum DeviceEnergyManagementDelegate::GetOptOutState() { + ChipLogDetail(AppServer, "mOptOutState %d", to_underlying(mOptOutState)); return mOptOutState; } @@ -323,28 +865,28 @@ CHIP_ERROR DeviceEnergyManagementDelegate::SetESAState(ESAStateEnum newValue) return CHIP_NO_ERROR; } -CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMinPower(int64_t newValue) +CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMinPower(int64_t newValueMw) { - int64_t oldValue = mAbsMinPower; + int64_t oldValueMw = mAbsMinPowerMw; - mAbsMinPower = newValue; - if (oldValue != newValue) + mAbsMinPowerMw = newValueMw; + if (oldValueMw != newValueMw) { - ChipLogDetail(AppServer, "mAbsMinPower updated to %d", static_cast(mAbsMinPower)); + ChipLogDetail(AppServer, "mAbsMinPower updated to " ChipLogFormatX64, ChipLogValueX64(mAbsMinPowerMw)); MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, AbsMinPower::Id); } return CHIP_NO_ERROR; } -CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMaxPower(int64_t newValue) +CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMaxPower(int64_t newValueMw) { - int64_t oldValue = mAbsMaxPower; + int64_t oldValueMw = mAbsMaxPowerMw; - mAbsMaxPower = newValue; - if (oldValue != newValue) + mAbsMaxPowerMw = newValueMw; + if (oldValueMw != newValueMw) { - ChipLogDetail(AppServer, "mAbsMaxPower updated to %d", static_cast(mAbsMaxPower)); + ChipLogDetail(AppServer, "mAbsMaxPower updated to " ChipLogFormatX64, ChipLogValueX64(mAbsMaxPowerMw)); MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, AbsMaxPower::Id); } @@ -352,20 +894,111 @@ CHIP_ERROR DeviceEnergyManagementDelegate::SetAbsMaxPower(int64_t newValue) } CHIP_ERROR -DeviceEnergyManagementDelegate::SetPowerAdjustmentCapability(PowerAdjustmentCapability::TypeInfo::Type powerAdjustmentCapability) +DeviceEnergyManagementDelegate::SetPowerAdjustmentCapability( + const DataModel::Nullable & powerAdjustCapabilityStruct) { - // TODO see Issue #31147 + assertChipStackLockedByCurrentThread(); + + mPowerAdjustCapabilityStruct = powerAdjustCapabilityStruct; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, PowerAdjustmentCapability::Id); + return CHIP_NO_ERROR; } -CHIP_ERROR DeviceEnergyManagementDelegate::SetForecast(DataModel::Nullable forecast) +CHIP_ERROR DeviceEnergyManagementDelegate::SetForecast(const DataModel::Nullable & forecast) { + assertChipStackLockedByCurrentThread(); + // TODO see Issue #31147 + mForecast = forecast; + + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, Forecast::Id); return CHIP_NO_ERROR; } CHIP_ERROR DeviceEnergyManagementDelegate::SetOptOutState(OptOutStateEnum newValue) { - return CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + + OptOutStateEnum oldValue = mOptOutState; + + // The OptOutState is cumulative + if ((oldValue == OptOutStateEnum::kGridOptOut && newValue == OptOutStateEnum::kLocalOptOut) || + (oldValue == OptOutStateEnum::kLocalOptOut && newValue == OptOutStateEnum::kGridOptOut)) + { + mOptOutState = OptOutStateEnum::kOptOut; + } + else + { + mOptOutState = newValue; + } + + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "mOptOutState updated to %d mPowerAdjustmentInProgress %d", to_underlying(mOptOutState), + mPowerAdjustmentInProgress); + MatterReportingAttributeChangeCallback(mEndpointId, DeviceEnergyManagement::Id, OptOutState::Id); + } + + // Cancel any outstanding PowerAdjustment if necessary + if (mPowerAdjustmentInProgress) + { + if ((newValue == OptOutStateEnum::kLocalOptOut && + mPowerAdjustCapabilityStruct.Value().cause == PowerAdjustReasonEnum::kLocalOptimizationAdjustment) || + (newValue == OptOutStateEnum::kGridOptOut && + mPowerAdjustCapabilityStruct.Value().cause == PowerAdjustReasonEnum::kGridOptimizationAdjustment) || + newValue == OptOutStateEnum::kOptOut) + { + err = CancelPowerAdjustRequestAndGenerateEvent(DeviceEnergyManagement::CauseEnum::kUserOptOut); + } + } + + // Cancel any outstanding PauseRequest if necessary + if (mPauseRequestInProgress) + { + // Cancel any outstanding PauseRequest + if ((newValue == OptOutStateEnum::kLocalOptOut && + mForecast.Value().forecastUpdateReason == ForecastUpdateReasonEnum::kLocalOptimization) || + (newValue == OptOutStateEnum::kGridOptOut && + mForecast.Value().forecastUpdateReason == ForecastUpdateReasonEnum::kGridOptimization) || + newValue == OptOutStateEnum::kOptOut) + { + err = CancelPauseRequestAndGenerateEvent(DeviceEnergyManagement::CauseEnum::kUserOptOut); + } + } + + if (!mForecast.IsNull()) + { + switch (mForecast.Value().forecastUpdateReason) + { + case ForecastUpdateReasonEnum::kInternalOptimization: + // We don't need to redo a forecast since its internal already + break; + case ForecastUpdateReasonEnum::kLocalOptimization: + if ((mOptOutState == OptOutStateEnum::kOptOut) || (mOptOutState == OptOutStateEnum::kLocalOptOut)) + { + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + // Generate a new forecast with Internal Optimization + // TODO + } + break; + case ForecastUpdateReasonEnum::kGridOptimization: + if ((mOptOutState == OptOutStateEnum::kOptOut) || (mOptOutState == OptOutStateEnum::kGridOptOut)) + { + mForecast.Value().forecastUpdateReason = ForecastUpdateReasonEnum::kInternalOptimization; + // Generate a new forecast with Internal Optimization + // TODO + } + break; + default: + ChipLogDetail(AppServer, "Bad ForecastUpdateReasonEnum value of %d", + to_underlying(mForecast.Value().forecastUpdateReason)); + return CHIP_ERROR_BAD_REQUEST; + break; + } + } + + return err; } diff --git a/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp index c31e0624e4c743..12f754a53ff804 100644 --- a/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp +++ b/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,16 @@ using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::DeviceEnergyManagement; +namespace chip { +namespace app { +namespace Clusters { + +DeviceEnergyManagementManager::DeviceEnergyManagementManager(EndpointId aEndpointId, DeviceEnergyManagementDelegate & aDelegate, + Feature aFeature) : + DeviceEnergyManagement::Instance(aEndpointId, aDelegate, aFeature), + mDelegate(&aDelegate) +{} + CHIP_ERROR DeviceEnergyManagementManager::Init() { return Instance::Init(); @@ -31,3 +41,7 @@ void DeviceEnergyManagementManager::Shutdown() { Instance::Shutdown(); } + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp index d9848bcbc53515..9006477b3662d5 100644 --- a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp +++ b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,9 +16,13 @@ * limitations under the License. */ +#include +#include #include #include +#include +#include #include #include #include @@ -58,6 +62,13 @@ CHIP_ERROR EVSEManufacturer::Init() ReturnErrorOnFailure(InitializePowerMeasurementCluster()); ReturnErrorOnFailure(InitializePowerSourceCluster()); + + DeviceEnergyManagementDelegate * dem = GetEvseManufacturer()->GetDEMDelegate(); + VerifyOrReturnLogError(dem != nullptr, CHIP_ERROR_UNINITIALIZED); + + /* For Device Energy Management we need the ESA to be Online and ready to accept commands */ + dem->SetESAState(ESAStateEnum::kOnline); + /* * This is an example implementation for manufacturers to consider * @@ -322,147 +333,6 @@ CHIP_ERROR EVSEManufacturer::SendPeriodicEnergyReading(EndpointId aEndpointId, i return CHIP_NO_ERROR; } -struct FakeReadingsData -{ - bool bEnabled; /* If enabled then the timer callback will re-trigger */ - EndpointId mEndpointId; /* Which endpoint the meter is on */ - uint8_t mInterval_s; /* Interval in seconds to callback */ - int64_t mPower_mW; /* Active Power on the load in mW (signed value) +ve = imported */ - uint32_t mPowerRandomness_mW; /* The amount to randomize the Power on the load in mW */ - int64_t mVoltage_mV; /* Voltage reading in mV (signed value) */ - uint32_t mVoltageRandomness_mV; /* The amount to randomize the Voltage in mV */ - int64_t mCurrent_mA; /* ActiveCurrent reading in mA (signed value) */ - uint32_t mCurrentRandomness_mA; /* The amount to randomize the ActiveCurrent in mA */ - - /* These energy values can only be positive values. - * however the underlying energy type (power_mWh) is signed, so keeping with that convention */ - int64_t mTotalEnergyImported = 0; /* Cumulative Energy Imported which is updated if mPower > 0 */ - int64_t mTotalEnergyExported = 0; /* Cumulative Energy Imported which is updated if mPower < 0 */ - int64_t mPeriodicEnergyImported = 0; /* Periodic Energy Imported which is updated if mPower > 0 */ - int64_t mPeriodicEnergyExported = 0; /* Periodic Energy Imported which is updated if mPower < 0 */ -}; - -static FakeReadingsData gFakeReadingsData; - -/* This helper routine starts and handles a callback */ -/** - * @brief Starts a fake load/generator to periodically callback the power and energy - * clusters. - * @param[in] aEndpointId - which endpoint is the meter to be updated on - * @param[in] aPower_mW - the mean power of the load - * Positive power indicates Imported energy (e.g. a load) - * Negative power indicated Exported energy (e.g. a generator) - * @param[in] aPowerRandomness_mW This is used to define the max randomness of the - * random power values around the mean power of the load - * @param[in] aVoltage_mV - the nominal voltage measurement - * @param[in] aVoltageRandomness_mV This is used to define the max randomness of the - * random voltage values - * @param[in] aCurrent_mA - the nominal current measurement - * @param[in] aCurrentRandomness_mA This is used to define the max randomness of the - * random current values - * @param[in] aInterval_s - the callback interval in seconds - * @param[in] bReset - boolean: true will reset the energy values to 0 - */ -void EVSEManufacturer::StartFakeReadings(EndpointId aEndpointId, int64_t aPower_mW, uint32_t aPowerRandomness_mW, - int64_t aVoltage_mV, uint32_t aVoltageRandomness_mV, int64_t aCurrent_mA, - uint32_t aCurrentRandomness_mA, uint8_t aInterval_s, bool bReset) -{ - gFakeReadingsData.bEnabled = true; - gFakeReadingsData.mEndpointId = aEndpointId; - gFakeReadingsData.mPower_mW = aPower_mW; - gFakeReadingsData.mPowerRandomness_mW = aPowerRandomness_mW; - gFakeReadingsData.mVoltage_mV = aVoltage_mV; - gFakeReadingsData.mVoltageRandomness_mV = aVoltageRandomness_mV; - gFakeReadingsData.mCurrent_mA = aCurrent_mA; - gFakeReadingsData.mCurrentRandomness_mA = aCurrentRandomness_mA; - gFakeReadingsData.mInterval_s = aInterval_s; - - if (bReset) - { - gFakeReadingsData.mTotalEnergyImported = 0; - gFakeReadingsData.mTotalEnergyExported = 0; - } - - // Call update function to kick off regular readings - FakeReadingsUpdate(); -} -/** - * @brief Stops any active updates to the fake load data callbacks - */ -void EVSEManufacturer::StopFakeReadings() -{ - gFakeReadingsData.bEnabled = false; -} -/** - * @brief Sends fake meter data into the cluster and restarts the timer - */ -void EVSEManufacturer::FakeReadingsUpdate() -{ - /* Check to see if the fake Load is still running - don't send updates if the timer was already cancelled */ - if (!gFakeReadingsData.bEnabled) - { - return; - } - - // Update readings - // Avoid using floats - so we will do a basic rand() call which will generate a integer value between 0 and RAND_MAX - // first compute power as a mean + some random value in range +/- mPowerRandomness_mW - int64_t power = - (static_cast(rand()) % (2 * gFakeReadingsData.mPowerRandomness_mW)) - gFakeReadingsData.mPowerRandomness_mW; - power += gFakeReadingsData.mPower_mW; // add in the base power - - int64_t voltage = - (static_cast(rand()) % (2 * gFakeReadingsData.mVoltageRandomness_mV)) - gFakeReadingsData.mVoltageRandomness_mV; - voltage += gFakeReadingsData.mVoltage_mV; // add in the base voltage - - /* Note: whilst we could compute a current from the power and voltage, - * there will always be some random error from the sensor - * that measures it. To keep this simple and to avoid doing divides in integer - * format etc use the same approach here too. - * This is meant more as an example to show how to use the APIs, not - * to be a real representation of laws of physics. - */ - int64_t current = - (static_cast(rand()) % (2 * gFakeReadingsData.mCurrentRandomness_mA)) - gFakeReadingsData.mCurrentRandomness_mA; - current += gFakeReadingsData.mCurrent_mA; // add in the base current - - SendPowerReading(gFakeReadingsData.mEndpointId, power, voltage, current); - - // update the energy meter - we'll assume that the power has been constant during the previous interval - if (gFakeReadingsData.mPower_mW > 0) - { - // Positive power - means power is imported - gFakeReadingsData.mPeriodicEnergyImported = ((power * gFakeReadingsData.mInterval_s) / 3600); - gFakeReadingsData.mPeriodicEnergyExported = 0; - gFakeReadingsData.mTotalEnergyImported += gFakeReadingsData.mPeriodicEnergyImported; - } - else - { - // Negative power - means power is exported, but the exported energy is reported positive - gFakeReadingsData.mPeriodicEnergyImported = 0; - gFakeReadingsData.mPeriodicEnergyExported = ((-power * gFakeReadingsData.mInterval_s) / 3600); - gFakeReadingsData.mTotalEnergyExported += gFakeReadingsData.mPeriodicEnergyExported; - } - - SendPeriodicEnergyReading(gFakeReadingsData.mEndpointId, gFakeReadingsData.mPeriodicEnergyImported, - gFakeReadingsData.mPeriodicEnergyExported); - - SendCumulativeEnergyReading(gFakeReadingsData.mEndpointId, gFakeReadingsData.mTotalEnergyImported, - gFakeReadingsData.mTotalEnergyExported); - - // start/restart the timer - DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(gFakeReadingsData.mInterval_s), FakeReadingsTimerExpiry, this); -} -/** - * @brief Timer expiry callback to handle fake load - */ -void EVSEManufacturer::FakeReadingsTimerExpiry(System::Layer * systemLayer, void * manufacturer) -{ - EVSEManufacturer * mn = reinterpret_cast(manufacturer); - - mn->FakeReadingsUpdate(); -} - /** * @brief Main Callback handler - to be implemented by Manufacturer * @@ -501,227 +371,65 @@ void EVSEManufacturer::ApplicationCallbackHandler(const EVSECbInfo * cb, intptr_ } } -struct EVSETestEventSaveData +// The PowerAdjustEnd event needs to report the approximate energy used by the ESA during the session. +int64_t EVSEManufacturer::GetApproxEnergyDuringSession() { - int64_t mOldMaxHardwareCurrentLimit; - int64_t mOldCircuitCapacity; - int64_t mOldUserMaximumChargeCurrent; - int64_t mOldCableAssemblyLimit; - StateEnum mOldHwStateBasic; /* For storing hwState before Basic Func event */ - StateEnum mOldHwStatePluggedIn; /* For storing hwState before PluggedIn event */ - StateEnum mOldHwStatePluggedInDemand; /* For storing hwState before PluggedInDemand event */ -}; - -static EVSETestEventSaveData sEVSETestEventSaveData; - -EnergyEvseDelegate * GetEvseDelegate() -{ - EVSEManufacturer * mn = GetEvseManufacturer(); - VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); - EnergyEvseDelegate * dg = mn->GetEvseDelegate(); - VerifyOrDieWithMsg(dg != nullptr, AppServer, "EVSE Delegate is null"); - - return dg; -} - -void SetTestEventTrigger_BasicFunctionality() -{ - EnergyEvseDelegate * dg = GetEvseDelegate(); - - sEVSETestEventSaveData.mOldMaxHardwareCurrentLimit = dg->HwGetMaxHardwareCurrentLimit(); - sEVSETestEventSaveData.mOldCircuitCapacity = dg->GetCircuitCapacity(); - sEVSETestEventSaveData.mOldUserMaximumChargeCurrent = dg->GetUserMaximumChargeCurrent(); - sEVSETestEventSaveData.mOldHwStateBasic = dg->HwGetState(); - - dg->HwSetMaxHardwareCurrentLimit(32000); - dg->HwSetCircuitCapacity(32000); - dg->SetUserMaximumChargeCurrent(32000); - dg->HwSetState(StateEnum::kNotPluggedIn); + return 300; } -void SetTestEventTrigger_BasicFunctionalityClear() -{ - EnergyEvseDelegate * dg = GetEvseDelegate(); - dg->HwSetMaxHardwareCurrentLimit(sEVSETestEventSaveData.mOldMaxHardwareCurrentLimit); - dg->HwSetCircuitCapacity(sEVSETestEventSaveData.mOldCircuitCapacity); - dg->SetUserMaximumChargeCurrent(sEVSETestEventSaveData.mOldUserMaximumChargeCurrent); - dg->HwSetState(sEVSETestEventSaveData.mOldHwStateBasic); -} -void SetTestEventTrigger_EVPluggedIn() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementPowerAdjustRequest(const int64_t powerMw, const uint32_t durationS, + AdjustmentCauseEnum cause) { - EnergyEvseDelegate * dg = GetEvseDelegate(); - - sEVSETestEventSaveData.mOldCableAssemblyLimit = dg->HwGetCableAssemblyLimit(); - sEVSETestEventSaveData.mOldHwStatePluggedIn = dg->HwGetState(); - - dg->HwSetCableAssemblyLimit(63000); - dg->HwSetState(StateEnum::kPluggedInNoDemand); -} -void SetTestEventTrigger_EVPluggedInClear() -{ - EnergyEvseDelegate * dg = GetEvseDelegate(); - dg->HwSetCableAssemblyLimit(sEVSETestEventSaveData.mOldCableAssemblyLimit); - dg->HwSetState(sEVSETestEventSaveData.mOldHwStatePluggedIn); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_EVChargeDemand() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementPowerAdjustCompletion() { - EnergyEvseDelegate * dg = GetEvseDelegate(); - - sEVSETestEventSaveData.mOldHwStatePluggedInDemand = dg->HwGetState(); - dg->HwSetState(StateEnum::kPluggedInDemand); -} -void SetTestEventTrigger_EVChargeDemandClear() -{ - EnergyEvseDelegate * dg = GetEvseDelegate(); - - dg->HwSetState(sEVSETestEventSaveData.mOldHwStatePluggedInDemand); -} -void SetTestEventTrigger_EVSEGroundFault() -{ - EnergyEvseDelegate * dg = GetEvseDelegate(); - - dg->HwSetFault(FaultStateEnum::kGroundFault); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_EVSEOverTemperatureFault() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementCancelPowerAdjustRequest(CauseEnum cause) { - EnergyEvseDelegate * dg = GetEvseDelegate(); - - dg->HwSetFault(FaultStateEnum::kOverTemperature); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_EVSEFaultClear() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementStartTimeAdjustRequest(const uint32_t requestedStartTimeUtc, + AdjustmentCauseEnum cause) { - EnergyEvseDelegate * dg = GetEvseDelegate(); - - dg->HwSetFault(FaultStateEnum::kNoError); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_EVSEDiagnosticsComplete() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementPauseRequest(const uint32_t durationS, AdjustmentCauseEnum cause) { - EnergyEvseDelegate * dg = GetEvseDelegate(); - - dg->HwDiagnosticsComplete(); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_FakeReadingsLoadStart() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementCancelPauseRequest(CauseEnum cause) { - EVSEManufacturer * mn = GetEvseManufacturer(); - VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); - - int64_t aPower_mW = 1'000'000; // Fake load 1000 W - uint32_t aPowerRandomness_mW = 20'000; // randomness 20W - int64_t aVoltage_mV = 230'000; // Fake Voltage 230V - uint32_t aVoltageRandomness_mV = 1'000; // randomness 1V - int64_t aCurrent_mA = 4'348; // Fake Current (at 1kW@230V = 4.3478 Amps) - uint32_t aCurrentRandomness_mA = 500; // randomness 500mA - uint8_t aInterval_s = 2; // 2s updates - bool bReset = true; - mn->StartFakeReadings(EndpointId(1), aPower_mW, aPowerRandomness_mW, aVoltage_mV, aVoltageRandomness_mV, aCurrent_mA, - aCurrentRandomness_mA, aInterval_s, bReset); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_FakeReadingsGeneratorStart() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementPauseCompletion() { - EVSEManufacturer * mn = GetEvseManufacturer(); - VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); - - int64_t aPower_mW = -3'000'000; // Fake Generator -3000 W - uint32_t aPowerRandomness_mW = 20'000; // randomness 20W - int64_t aVoltage_mV = 230'000; // Fake Voltage 230V - uint32_t aVoltageRandomness_mV = 1'000; // randomness 1V - int64_t aCurrent_mA = -13'043; // Fake Current (at -3kW@230V = -13.0434 Amps) - uint32_t aCurrentRandomness_mA = 500; // randomness 500mA - uint8_t aInterval_s = 5; // 5s updates - bool bReset = true; - mn->StartFakeReadings(EndpointId(1), aPower_mW, aPowerRandomness_mW, aVoltage_mV, aVoltageRandomness_mV, aCurrent_mA, - aCurrentRandomness_mA, aInterval_s, bReset); + return CHIP_NO_ERROR; } -void SetTestEventTrigger_FakeReadingsStop() +CHIP_ERROR EVSEManufacturer::HandleDeviceEnergyManagementCancelRequest() { - EVSEManufacturer * mn = GetEvseManufacturer(); - VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); - mn->StopFakeReadings(); + return CHIP_NO_ERROR; } -bool HandleEnergyEvseTestEventTrigger(uint64_t eventTrigger) +CHIP_ERROR EVSEManufacturer::HandleModifyForecastRequest( + const uint32_t forecastID, + const DataModel::DecodableList & slotAdjustments, + AdjustmentCauseEnum cause) { - EnergyEvseTrigger trigger = static_cast(eventTrigger); - - switch (trigger) - { - case EnergyEvseTrigger::kBasicFunctionality: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => Basic Functionality install"); - SetTestEventTrigger_BasicFunctionality(); - break; - case EnergyEvseTrigger::kBasicFunctionalityClear: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => Basic Functionality clear"); - SetTestEventTrigger_BasicFunctionalityClear(); - break; - case EnergyEvseTrigger::kEVPluggedIn: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV plugged in"); - SetTestEventTrigger_EVPluggedIn(); - break; - case EnergyEvseTrigger::kEVPluggedInClear: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV unplugged"); - SetTestEventTrigger_EVPluggedInClear(); - break; - case EnergyEvseTrigger::kEVChargeDemand: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV Charge Demand"); - SetTestEventTrigger_EVChargeDemand(); - break; - case EnergyEvseTrigger::kEVChargeDemandClear: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV Charge NoDemand"); - SetTestEventTrigger_EVChargeDemandClear(); - break; - case EnergyEvseTrigger::kEVSEGroundFault: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE has a GroundFault fault"); - SetTestEventTrigger_EVSEGroundFault(); - break; - case EnergyEvseTrigger::kEVSEOverTemperatureFault: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE has a OverTemperature fault"); - SetTestEventTrigger_EVSEOverTemperatureFault(); - break; - case EnergyEvseTrigger::kEVSEFaultClear: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE faults have cleared"); - SetTestEventTrigger_EVSEFaultClear(); - break; - case EnergyEvseTrigger::kEVSEDiagnosticsComplete: - ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE Diagnostics Completed"); - SetTestEventTrigger_EVSEDiagnosticsComplete(); - break; - - default: - return false; - } - - return true; + return CHIP_NO_ERROR; } -bool HandleEnergyReportingTestEventTrigger(uint64_t eventTrigger) +CHIP_ERROR EVSEManufacturer::RequestConstraintBasedForecast( + const DataModel::DecodableList & constraints, + AdjustmentCauseEnum cause) { - EnergyReportingTrigger trigger = static_cast(eventTrigger); - - switch (trigger) - { - case EnergyReportingTrigger::kFakeReadingsStop: - ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Stop Fake load"); - SetTestEventTrigger_FakeReadingsStop(); - break; - case EnergyReportingTrigger::kFakeReadingsLoadStart_1kW_2s: - ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Start Fake load 1kW @2s Import"); - SetTestEventTrigger_FakeReadingsLoadStart(); - break; - case EnergyReportingTrigger::kFakeReadingsGenStart_3kW_5s: - ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Start Fake generator 3kW @5s Export"); - SetTestEventTrigger_FakeReadingsGeneratorStart(); - break; - - default: - return false; - } - - return true; + return CHIP_NO_ERROR; } diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp index 99619fc95b5fb0..b0cfd6fc5ce0ef 100644 --- a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseEventTriggers.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseEventTriggers.cpp new file mode 100644 index 00000000000000..62329068610f47 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseEventTriggers.cpp @@ -0,0 +1,184 @@ +/* + * + * 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 + +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::EnergyEvse; + +struct EVSETestEventSaveData +{ + int64_t mOldMaxHardwareCurrentLimit; + int64_t mOldCircuitCapacity; + int64_t mOldUserMaximumChargeCurrent; + int64_t mOldCableAssemblyLimit; + StateEnum mOldHwStateBasic; /* For storing hwState before Basic Func event */ + StateEnum mOldHwStatePluggedIn; /* For storing hwState before PluggedIn event */ + StateEnum mOldHwStatePluggedInDemand; /* For storing hwState before PluggedInDemand event */ +}; + +static EVSETestEventSaveData sEVSETestEventSaveData; + +EnergyEvseDelegate * GetEvseDelegate() +{ + EVSEManufacturer * mn = GetEvseManufacturer(); + VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null"); + EnergyEvseDelegate * dg = mn->GetEvseDelegate(); + VerifyOrDieWithMsg(dg != nullptr, AppServer, "EVSE Delegate is null"); + + return dg; +} + +void SetTestEventTrigger_BasicFunctionality() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + sEVSETestEventSaveData.mOldMaxHardwareCurrentLimit = dg->HwGetMaxHardwareCurrentLimit(); + sEVSETestEventSaveData.mOldCircuitCapacity = dg->GetCircuitCapacity(); + sEVSETestEventSaveData.mOldUserMaximumChargeCurrent = dg->GetUserMaximumChargeCurrent(); + sEVSETestEventSaveData.mOldHwStateBasic = dg->HwGetState(); + + dg->HwSetMaxHardwareCurrentLimit(32000); + dg->HwSetCircuitCapacity(32000); + dg->SetUserMaximumChargeCurrent(32000); + dg->HwSetState(StateEnum::kNotPluggedIn); +} +void SetTestEventTrigger_BasicFunctionalityClear() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + dg->HwSetMaxHardwareCurrentLimit(sEVSETestEventSaveData.mOldMaxHardwareCurrentLimit); + dg->HwSetCircuitCapacity(sEVSETestEventSaveData.mOldCircuitCapacity); + dg->SetUserMaximumChargeCurrent(sEVSETestEventSaveData.mOldUserMaximumChargeCurrent); + dg->HwSetState(sEVSETestEventSaveData.mOldHwStateBasic); +} +void SetTestEventTrigger_EVPluggedIn() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + sEVSETestEventSaveData.mOldCableAssemblyLimit = dg->HwGetCableAssemblyLimit(); + sEVSETestEventSaveData.mOldHwStatePluggedIn = dg->HwGetState(); + + dg->HwSetCableAssemblyLimit(63000); + dg->HwSetState(StateEnum::kPluggedInNoDemand); +} +void SetTestEventTrigger_EVPluggedInClear() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + dg->HwSetCableAssemblyLimit(sEVSETestEventSaveData.mOldCableAssemblyLimit); + dg->HwSetState(sEVSETestEventSaveData.mOldHwStatePluggedIn); +} + +void SetTestEventTrigger_EVChargeDemand() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + sEVSETestEventSaveData.mOldHwStatePluggedInDemand = dg->HwGetState(); + dg->HwSetState(StateEnum::kPluggedInDemand); +} +void SetTestEventTrigger_EVChargeDemandClear() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + dg->HwSetState(sEVSETestEventSaveData.mOldHwStatePluggedInDemand); +} +void SetTestEventTrigger_EVSEGroundFault() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + dg->HwSetFault(FaultStateEnum::kGroundFault); +} + +void SetTestEventTrigger_EVSEOverTemperatureFault() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + dg->HwSetFault(FaultStateEnum::kOverTemperature); +} + +void SetTestEventTrigger_EVSEFaultClear() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + dg->HwSetFault(FaultStateEnum::kNoError); +} + +void SetTestEventTrigger_EVSEDiagnosticsComplete() +{ + EnergyEvseDelegate * dg = GetEvseDelegate(); + + dg->HwDiagnosticsComplete(); +} + +bool HandleEnergyEvseTestEventTrigger(uint64_t eventTrigger) +{ + EnergyEvseTrigger trigger = static_cast(eventTrigger); + + switch (trigger) + { + case EnergyEvseTrigger::kBasicFunctionality: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => Basic Functionality install"); + SetTestEventTrigger_BasicFunctionality(); + break; + case EnergyEvseTrigger::kBasicFunctionalityClear: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => Basic Functionality clear"); + SetTestEventTrigger_BasicFunctionalityClear(); + break; + case EnergyEvseTrigger::kEVPluggedIn: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV plugged in"); + SetTestEventTrigger_EVPluggedIn(); + break; + case EnergyEvseTrigger::kEVPluggedInClear: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV unplugged"); + SetTestEventTrigger_EVPluggedInClear(); + break; + case EnergyEvseTrigger::kEVChargeDemand: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV Charge Demand"); + SetTestEventTrigger_EVChargeDemand(); + break; + case EnergyEvseTrigger::kEVChargeDemandClear: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV Charge NoDemand"); + SetTestEventTrigger_EVChargeDemandClear(); + break; + case EnergyEvseTrigger::kEVSEGroundFault: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE has a GroundFault fault"); + SetTestEventTrigger_EVSEGroundFault(); + break; + case EnergyEvseTrigger::kEVSEOverTemperatureFault: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE has a OverTemperature fault"); + SetTestEventTrigger_EVSEOverTemperatureFault(); + break; + case EnergyEvseTrigger::kEVSEFaultClear: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE faults have cleared"); + SetTestEventTrigger_EVSEFaultClear(); + break; + case EnergyEvseTrigger::kEVSEDiagnosticsComplete: + ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE Diagnostics Completed"); + SetTestEventTrigger_EVSEDiagnosticsComplete(); + break; + + default: + return false; + } + + return true; +} diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseMain.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseMain.cpp index 6eeaaf8369c38c..0a4bc0456e2254 100644 --- a/examples/energy-management-app/energy-management-common/src/EnergyEvseMain.cpp +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseMain.cpp @@ -16,6 +16,8 @@ * limitations under the License. */ +#include "EnergyManagementAppCmdLineOptions.h" + #include #include #include @@ -86,13 +88,10 @@ CHIP_ERROR DeviceEnergyManagementInit() return CHIP_ERROR_NO_MEMORY; } + BitMask featureMap = GetFeatureMapFromCmdLine(); + /* Manufacturer may optionally not support all features, commands & attributes */ - gDEMInstance = std::make_unique( - EndpointId(ENERGY_EVSE_ENDPOINT), *gDEMDelegate, - BitMask( - DeviceEnergyManagement::Feature::kPowerAdjustment, DeviceEnergyManagement::Feature::kPowerForecastReporting, - DeviceEnergyManagement::Feature::kStateForecastReporting, DeviceEnergyManagement::Feature::kStartTimeAdjustment, - DeviceEnergyManagement::Feature::kPausable)); + gDEMInstance = std::make_unique(EndpointId(ENERGY_EVSE_ENDPOINT), *gDEMDelegate, featureMap); if (!gDEMInstance) { @@ -101,6 +100,8 @@ CHIP_ERROR DeviceEnergyManagementInit() return CHIP_ERROR_NO_MEMORY; } + gDEMDelegate->SetDeviceEnergyManagementInstance(*gDEMInstance); + CHIP_ERROR err = gDEMInstance->Init(); /* Register Attribute & Command handlers */ if (err != CHIP_NO_ERROR) { @@ -375,13 +376,16 @@ CHIP_ERROR EVSEManufacturerInit() } /* Now create EVSEManufacturer */ - gEvseManufacturer = std::make_unique(gEvseInstance.get(), gEPMInstance.get(), gPTInstance.get()); + gEvseManufacturer = + std::make_unique(gEvseInstance.get(), gEPMInstance.get(), gPTInstance.get(), gDEMInstance.get()); if (!gEvseManufacturer) { ChipLogError(AppServer, "Failed to allocate memory for EvseManufacturer"); return CHIP_ERROR_NO_MEMORY; } + gDEMDelegate.get()->SetDEMManufacturerDelegate(*gEvseManufacturer.get()); + /* Call Manufacturer specific init */ err = gEvseManufacturer->Init(); if (err != CHIP_NO_ERROR) diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp index f4b3941e8c1ca7..c8b43342f8bd1c 100644 --- a/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/energy-management-app/energy-management-common/src/EnergyReportingEventTriggers.cpp b/examples/energy-management-app/energy-management-common/src/EnergyReportingEventTriggers.cpp new file mode 100644 index 00000000000000..e01612a5f408d3 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EnergyReportingEventTriggers.cpp @@ -0,0 +1,85 @@ +/* + * + * 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 "FakeReadings.h" + +#include + +using namespace chip; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::ElectricalEnergyMeasurement; +using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Structs; + +void SetTestEventTrigger_FakeReadingsLoadStart() +{ + int64_t aPower_mW = 1'000'000; // Fake load 1000 W + uint32_t aPowerRandomness_mW = 20'000; // randomness 20W + int64_t aVoltage_mV = 230'000; // Fake Voltage 230V + uint32_t aVoltageRandomness_mV = 1'000; // randomness 1V + int64_t aCurrent_mA = 4'348; // Fake Current (at 1kW@230V = 4.3478 Amps) + uint32_t aCurrentRandomness_mA = 500; // randomness 500mA + uint8_t aInterval_s = 2; // 2s updates + bool bReset = true; + FakeReadings::GetInstance().StartFakeReadings(EndpointId(1), aPower_mW, aPowerRandomness_mW, aVoltage_mV, aVoltageRandomness_mV, + aCurrent_mA, aCurrentRandomness_mA, aInterval_s, bReset); +} + +void SetTestEventTrigger_FakeReadingsGeneratorStart() +{ + int64_t aPower_mW = -3'000'000; // Fake Generator -3000 W + uint32_t aPowerRandomness_mW = 20'000; // randomness 20W + int64_t aVoltage_mV = 230'000; // Fake Voltage 230V + uint32_t aVoltageRandomness_mV = 1'000; // randomness 1V + int64_t aCurrent_mA = -13'043; // Fake Current (at -3kW@230V = -13.0434 Amps) + uint32_t aCurrentRandomness_mA = 500; // randomness 500mA + uint8_t aInterval_s = 5; // 5s updates + bool bReset = true; + FakeReadings::GetInstance().StartFakeReadings(EndpointId(1), aPower_mW, aPowerRandomness_mW, aVoltage_mV, aVoltageRandomness_mV, + aCurrent_mA, aCurrentRandomness_mA, aInterval_s, bReset); +} + +void SetTestEventTrigger_FakeReadingsStop() +{ + FakeReadings::GetInstance().StopFakeReadings(); +} + +bool HandleEnergyReportingTestEventTrigger(uint64_t eventTrigger) +{ + EnergyReportingTrigger trigger = static_cast(eventTrigger); + + switch (trigger) + { + case EnergyReportingTrigger::kFakeReadingsStop: + ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Stop Fake load"); + SetTestEventTrigger_FakeReadingsStop(); + break; + case EnergyReportingTrigger::kFakeReadingsLoadStart_1kW_2s: + ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Start Fake load 1kW @2s Import"); + SetTestEventTrigger_FakeReadingsLoadStart(); + break; + case EnergyReportingTrigger::kFakeReadingsGenStart_3kW_5s: + ChipLogProgress(Support, "[EnergyReporting-Test-Event] => Start Fake generator 3kW @5s Export"); + SetTestEventTrigger_FakeReadingsGeneratorStart(); + break; + + default: + return false; + } + + return true; +} diff --git a/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp b/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp new file mode 100644 index 00000000000000..60732c0f3b0497 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp @@ -0,0 +1,153 @@ +/* + * + * 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 +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::EnergyEvse; +using namespace chip::app::Clusters::EnergyEvse::Attributes; + +using chip::app::LogEvent; +using chip::Protocols::InteractionModel::Status; + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +/** + * @brief Helper function to get current timestamp in Epoch format + * + * @param[out] chipEpoch reference to hold return timestamp. Set to 0 if an error occurs. + */ +CHIP_ERROR GetEpochTS(uint32_t & chipEpoch) +{ + chipEpoch = 0; + + System::Clock::Milliseconds64 cTMs; + CHIP_ERROR err = System::SystemClock().GetClock_RealTimeMS(cTMs); + + /* If the GetClock_RealTimeMS returns CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE, then + * This platform cannot ever report real time ! + * This should not be certifiable since getting time is a Mandatory + * feature of EVSE Cluster + */ + VerifyOrDie(err != CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Unable to get current time - err:%" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + + auto unixEpoch = std::chrono::duration_cast(cTMs).count(); + if (!UnixEpochToChipEpochTime(unixEpoch, chipEpoch)) + { + ChipLogError(Zcl, "Unable to convert Unix Epoch time to Matter Epoch Time"); + return CHIP_ERROR_INCORRECT_STATE; + } + + return CHIP_NO_ERROR; +} + +/** + * @brief Helper function to get current timestamp and work out the day of week + * + * NOTE that the time_t is converted using localtime to provide the timestamp + * in local time. If this is not supported on some platforms an alternative + * implementation may be required. + * + * @param unixEpoch (as time_t) + * + * @return bitmap value for day of week as defined by EnergyEvse::TargetDayOfWeekBitmap. Note + * only one bit will be set for the day of the week. + */ +BitMask GetLocalDayOfWeekFromUnixEpoch(time_t unixEpoch) +{ + // Define a timezone structure and initialize it to the local timezone + // This will capture any daylight saving time changes + struct tm local_time; + localtime_r(&unixEpoch, &local_time); + + // Get the day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday) + uint8_t dayOfWeek = static_cast(local_time.tm_wday); + + // Calculate the bitmap value based on the day of the week. Note that the value in bitmap + // maps directly to the definition in EnergyEvse::TargetDayOfWeekBitmap. + uint8_t bitmap = static_cast(1 << dayOfWeek); + + return bitmap; +} +/** + * @brief Helper function to get current timestamp and work out the day of week based on localtime + * + * @return bitmap value for day of week as defined by EnergyEvse::TargetDayOfWeekBitmap. Note + * only one bit will be set for the current day. + */ +CHIP_ERROR GetLocalDayOfWeekNow(BitMask & dayOfWeekMap) +{ + System::Clock::Milliseconds64 cTMs; + CHIP_ERROR err = chip::System::SystemClock().GetClock_RealTimeMS(cTMs); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Uable to get current time. error=%" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + time_t unixEpoch = std::chrono::duration_cast(cTMs).count(); + dayOfWeekMap = GetLocalDayOfWeekFromUnixEpoch(unixEpoch); + + return CHIP_NO_ERROR; +} + +/** + * @brief Helper function to get current timestamp and work out the current number of minutes + * past midnight based on localtime + * + * @param reference to hold the number of minutes past midnight + */ +CHIP_ERROR GetMinutesPastMidnight(uint16_t & minutesPastMidnight) +{ + System::Clock::Milliseconds64 cTMs; + CHIP_ERROR err = System::SystemClock().GetClock_RealTimeMS(cTMs); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "EVSE: unable to get current time to check user schedules error=%" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + time_t unixEpoch = std::chrono::duration_cast(cTMs).count(); + + // Define a timezone structure and initialize it to the local timezone + // This will capture any daylight saving time changes + struct tm local_time; + localtime_r(&unixEpoch, &local_time); + + minutesPastMidnight = static_cast((local_time.tm_hour * 60) + local_time.tm_min); + + return err; +} + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/src/FakeReadings.cpp b/examples/energy-management-app/energy-management-common/src/FakeReadings.cpp new file mode 100644 index 00000000000000..151e82be8436e9 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/FakeReadings.cpp @@ -0,0 +1,176 @@ +/* + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "FakeReadings.h" + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::EnergyEvse; +using namespace chip::app::Clusters::ElectricalPowerMeasurement; +using namespace chip::app::Clusters::ElectricalEnergyMeasurement; +using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Structs; +using namespace chip::app::Clusters::PowerSource; +using namespace chip::app::Clusters::PowerSource::Attributes; + +using Protocols::InteractionModel::Status; + +FakeReadings::FakeReadings() {} + +FakeReadings::~FakeReadings() {} + +/* static */ +FakeReadings & FakeReadings::GetInstance() +{ + static FakeReadings sInstance; + + return sInstance; +} + +/** + * @brief Starts a fake load/generator to periodically callback the power and energy + * clusters. + * @param[in] aEndpointId - which endpoint is the meter to be updated on + * @param[in] aPower_mW - the mean power of the load + * Positive power indicates Imported energy (e.g. a load) + * Negative power indicated Exported energy (e.g. a generator) + * @param[in] aPowerRandomness_mW This is used to define the max randomness of the + * random power values around the mean power of the load + * @param[in] aVoltage_mV - the nominal voltage measurement + * @param[in] aVoltageRandomness_mV This is used to define the max randomness of the + * random voltage values + * @param[in] aCurrent_mA - the nominal current measurement + * @param[in] aCurrentRandomness_mA This is used to define the max randomness of the + * random current values + * @param[in] aInterval_s - the callback interval in seconds + * @param[in] bReset - boolean: true will reset the energy values to 0 + */ +void FakeReadings::StartFakeReadings(EndpointId aEndpointId, int64_t aPower_mW, uint32_t aPowerRandomness_mW, int64_t aVoltage_mV, + uint32_t aVoltageRandomness_mV, int64_t aCurrent_mA, uint32_t aCurrentRandomness_mA, + uint8_t aInterval_s, bool bReset) +{ + bEnabled = true; + mEndpointId = aEndpointId; + mPower_mW = aPower_mW; + mPowerRandomness_mW = aPowerRandomness_mW; + mVoltage_mV = aVoltage_mV; + mVoltageRandomness_mV = aVoltageRandomness_mV; + mCurrent_mA = aCurrent_mA; + mCurrentRandomness_mA = aCurrentRandomness_mA; + mInterval_s = aInterval_s; + + if (bReset) + { + mTotalEnergyImported = 0; + mTotalEnergyExported = 0; + } + + // Call update function to kick off regular readings + FakeReadingsUpdate(); +} + +/** + * @brief Stops any active updates to the fake load data callbacks + */ +void FakeReadings::StopFakeReadings() +{ + bEnabled = false; +} + +/** + * @brief Sends fake meter data into the cluster and restarts the timer + */ +void FakeReadings::FakeReadingsUpdate() +{ + /* Check to see if the fake Load is still running - don't send updates if the timer was already cancelled */ + if (!bEnabled) + { + return; + } + + // Update readings + // Avoid using floats - so we will do a basic rand() call which will generate a integer value between 0 and RAND_MAX + // first compute power as a mean + some random value in range +/- mPowerRandomness_mW + int64_t power = (static_cast(rand()) % (2 * mPowerRandomness_mW)) - mPowerRandomness_mW; + power += mPower_mW; // add in the base power + + int64_t voltage = (static_cast(rand()) % (2 * mVoltageRandomness_mV)) - mVoltageRandomness_mV; + voltage += mVoltage_mV; // add in the base voltage + + /* Note: whilst we could compute a current from the power and voltage, + * there will always be some random error from the sensor + * that measures it. To keep this simple and to avoid doing divides in integer + * format etc use the same approach here too. + * This is meant more as an example to show how to use the APIs, not + * to be a real representation of laws of physics. + */ + int64_t current = (static_cast(rand()) % (2 * mCurrentRandomness_mA)) - mCurrentRandomness_mA; + current += mCurrent_mA; // add in the base current + + GetEvseManufacturer()->SendPowerReading(mEndpointId, power, voltage, current); + + // update the energy meter - we'll assume that the power has been constant during the previous interval + if (mPower_mW > 0) + { + // Positive power - means power is imported + mPeriodicEnergyImported = ((power * mInterval_s) / 3600); + mPeriodicEnergyExported = 0; + mTotalEnergyImported += mPeriodicEnergyImported; + } + else + { + // Negative power - means power is exported, but the exported energy is reported positive + mPeriodicEnergyImported = 0; + mPeriodicEnergyExported = ((-power * mInterval_s) / 3600); + mTotalEnergyExported += mPeriodicEnergyExported; + } + + GetEvseManufacturer()->SendPeriodicEnergyReading(mEndpointId, mPeriodicEnergyImported, mPeriodicEnergyExported); + + GetEvseManufacturer()->SendCumulativeEnergyReading(mEndpointId, mTotalEnergyImported, mTotalEnergyExported); + + // start/restart the timer + DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds32(mInterval_s), FakeReadingsTimerExpiry, this); +} + +/** + * @brief Timer expiry callback to handle fake load + */ +void FakeReadings::FakeReadingsTimerExpiry(System::Layer * systemLayer, void * manufacturer) +{ + FakeReadings * mn = reinterpret_cast(manufacturer); + + mn->FakeReadingsUpdate(); +} diff --git a/examples/energy-management-app/esp32/main/CMakeLists.txt b/examples/energy-management-app/esp32/main/CMakeLists.txt index a9a8c4100ae2de..15c1f99a6982aa 100644 --- a/examples/energy-management-app/esp32/main/CMakeLists.txt +++ b/examples/energy-management-app/esp32/main/CMakeLists.txt @@ -20,6 +20,7 @@ set(PRIV_INCLUDE_DIRS_LIST "${APP_GEN_DIR}" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/energy-management-common/include" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/energy-management-app/esp32/main/include" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32" ) diff --git a/examples/energy-management-app/esp32/main/include/CHIPProjectConfig.h b/examples/energy-management-app/esp32/main/include/CHIPProjectConfig.h index 559895608a08d0..b70a285ccfda0b 100644 --- a/examples/energy-management-app/esp32/main/include/CHIPProjectConfig.h +++ b/examples/energy-management-app/esp32/main/include/CHIPProjectConfig.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/energy-management-app/esp32/main/main.cpp b/examples/energy-management-app/esp32/main/main.cpp index e61e6cb00cca9b..136817a7744095 100644 --- a/examples/energy-management-app/esp32/main/main.cpp +++ b/examples/energy-management-app/esp32/main/main.cpp @@ -111,6 +111,26 @@ chip::Credentials::DeviceAttestationCredentialsProvider * get_dac_provider(void) } // namespace +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +// Keep track of the parsed featureMap option +static chip::BitMask sFeatureMap(Feature::kPowerAdjustment, Feature::kPowerForecastReporting, + Feature::kStateForecastReporting, Feature::kStartTimeAdjustment, Feature::kPausable, + Feature::kForecastAdjustment, Feature::kConstraintBasedAdjustment); + +chip::BitMask GetFeatureMapFromCmdLine() +{ + return sFeatureMap; +} + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip + void ApplicationInit() { ESP_LOGD(TAG, "Energy Management App: ApplicationInit()"); diff --git a/examples/energy-management-app/esp32/sdkconfig.optimize.defaults b/examples/energy-management-app/esp32/sdkconfig.optimize.defaults index 87248eebfcdfa7..85a5c0cbd4615c 100644 --- a/examples/energy-management-app/esp32/sdkconfig.optimize.defaults +++ b/examples/energy-management-app/esp32/sdkconfig.optimize.defaults @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Project CHIP Authors +# Copyright (c) 2023-2024 Project CHIP Authors # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/energy-management-app/linux/BUILD.gn b/examples/energy-management-app/linux/BUILD.gn index 4730c2c8ea82f3..c3564c345a1182 100644 --- a/examples/energy-management-app/linux/BUILD.gn +++ b/examples/energy-management-app/linux/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Project CHIP Authors +# Copyright (c) 2023-2024 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. @@ -36,13 +36,18 @@ config("includes") { executable("chip-energy-management-app") { sources = [ + "${chip_root}/examples/energy-management-app/energy-management-common/src/DEMTestEventTriggers.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseEventTriggers.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseMain.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyReportingEventTriggers.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/FakeReadings.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/PowerTopologyDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/device-energy-management-mode.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/energy-evse-mode.cpp", diff --git a/examples/energy-management-app/linux/README.md b/examples/energy-management-app/linux/README.md index f91d341915ccd8..ab35600709de47 100644 --- a/examples/energy-management-app/linux/README.md +++ b/examples/energy-management-app/linux/README.md @@ -163,6 +163,14 @@ There are several test scripts provided for EVSE (in - `TC_EEVSE_2_3`: This validates Get/Set/Clear target commands - `TC_EEVSE_2_4`: This validates Faults - `TC_EEVSE_2_5`: This validates EVSE diagnostic command (optional) +- `TC_EEVSE_2_6`: This validates EVSE Forecast Adjustment with State Forecast + Reporting feature functionality +- `TC_EEVSE_2_7`: This validates EVSE Constraints-based Adjustment with Power + Forecast Reporting feature functionality +- `TC_EEVSE_2_8`: This validates EVSE Constraints-based Adjustment with State + Forecast Reporting feature functionality +- `TC_EEVSE_2_9`: This validates EVSE Power or State Forecast Reporting + feature functionality These scripts require the use of Test Event Triggers via the GeneralDiagnostics cluster on Endpoint 0. This requires an `enableKey` (16 bytes) and a set of @@ -183,6 +191,39 @@ chosen enable key is using the `--enable-key` command line option. From the top-level of the connectedhomeip repo type: +Start the chip-energy-management-app: + +```bash +rm -f evse.bin; out/debug/chip-energy-management-app --enable-key 000102030405060708090a0b0c0d0e0f --KVS evse.bin --featureSet $featureSet +``` + +where the \$featureSet depends on the test being run: + +``` +TC_DEM_2_2.py: 0x01 // PA +TC_DEM_2_3.py: 0x3b // STA, PAU, FA, CON + (PFR | SFR) +TC_DEM_2_4.py: 0x3b // STA, PAU, FA, CON + (PFR | SFR) +TC_DEM_2_5.py: 0x3b // STA, PAU, FA, CON + PFR +TC_DEM_2_6.py: 0x3d // STA, PAU, FA, CON + SFR +TC_DEM_2_7.py: 0x3b // STA, PAU, FA, CON + PFR +TC_DEM_2_8.py: 0x3d // STA, PAU, FA, CON + SFR +TC_DEM_2_9.py: 0x3f // STA, PAU, FA, CON + PFR + SFR +``` + +where + +``` +PA - DEM.S.F00(PowerAdjustment) +PFR - DEM.S.F01(PowerForecastReporting) +SFR - DEM.S.F02(StateForecastReporting) +STA - DEM.S.F03(StartTimeAdjustment) +PAU - DEM.S.F04(Pausable) +FA - DEM.S.F05(ForecastAdjustment) +CON -DEM.S.F06(ConstraintBasedAdjustment) +``` + +Then run the test: + ```bash $ python src/python_testing/TC_EEVSE_2_2.py --endpoint 1 -m on-network -n 1234 -p 20202021 -d 3840 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f ``` @@ -191,6 +232,12 @@ From the top-level of the connectedhomeip repo type: cluster is on endpoint 1. The `--hex-arg enableKey:` value must match the `--enable-key ` used on chip-energy-management-app args. +The chip-energy-management-app will need to be stopped before running each test +script as each test commissions the chip-energy-management-app in the first +step. That is also why the evse.bin is deleted before running +chip-energy-management-app as this is where the app stores the matter persistent +data (e.g. fabric info). + ## CHIP-REPL Interaction - See chip-repl documentation in diff --git a/examples/energy-management-app/linux/args.gni b/examples/energy-management-app/linux/args.gni index e1000e6cb3fa27..1f196e6122910c 100644 --- a/examples/energy-management-app/linux/args.gni +++ b/examples/energy-management-app/linux/args.gni @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Project CHIP Authors +# Copyright (c) 2023-2024 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. @@ -31,3 +31,4 @@ matter_enable_tracing_support = true chip_enable_read_client = false chip_enable_energy_evse_trigger = true chip_enable_energy_reporting_trigger = true +chip_enable_device_energy_management_trigger = true diff --git a/examples/energy-management-app/linux/main.cpp b/examples/energy-management-app/linux/main.cpp index 7973c16025d640..2d056e56a9b149 100644 --- a/examples/energy-management-app/linux/main.cpp +++ b/examples/energy-management-app/linux/main.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,71 @@ #include #include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; +using namespace chip::app::Clusters::DeviceEnergyManagement::Attributes; + +// Parse a hex (prefixed by 0x) or decimal (no-prefix) string +static uint32_t ParseNumber(const char * pString); + +// Parses the --featureMap option +static bool FeatureMapOptionHandler(const char * aProgram, chip::ArgParser::OptionSet * aOptions, int aIdentifier, + const char * aName, const char * aValue); + +constexpr uint16_t kOptionFeatureMap = 'f'; + +// Define the chip::ArgParser command line structures for extending the command line to support the +// -f/--featureMap option +static chip::ArgParser::OptionDef sFeatureMapOptionDefs[] = { + { "featureSet", chip::ArgParser::kArgumentRequired, kOptionFeatureMap }, { NULL } +}; + +static chip::ArgParser::OptionSet sCmdLineOptions = { + FeatureMapOptionHandler, // handler function + sFeatureMapOptionDefs, // array of option definitions + "GENERAL OPTIONS", // help group + "-f, --featureSet " // option help text +}; + +namespace chip { +namespace app { +namespace Clusters { +namespace DeviceEnergyManagement { + +// Keep track of the parsed featureMap option +static chip::BitMask sFeatureMap(Feature::kPowerAdjustment, Feature::kPowerForecastReporting, + Feature::kStateForecastReporting, Feature::kStartTimeAdjustment, Feature::kPausable, + Feature::kForecastAdjustment, Feature::kConstraintBasedAdjustment); + +chip::BitMask GetFeatureMapFromCmdLine() +{ + return sFeatureMap; +} + +} // namespace DeviceEnergyManagement +} // namespace Clusters +} // namespace app +} // namespace chip + +static uint32_t ParseNumber(const char * pString) +{ + uint32_t num = 0; + if (strlen(pString) > 2 && pString[0] == '0' && pString[1] == 'x') + { + num = (uint32_t) strtoul(&pString[2], NULL, 16); + } + else + { + num = (uint32_t) strtoul(pString, NULL, 10); + } + + return num; +} void ApplicationInit() { @@ -31,9 +96,29 @@ void ApplicationShutdown() EvseApplicationShutdown(); } +static bool FeatureMapOptionHandler(const char * aProgram, chip::ArgParser::OptionSet * aOptions, int aIdentifier, + const char * aName, const char * aValue) +{ + bool retval = true; + + switch (aIdentifier) + { + case kOptionFeatureMap: + sFeatureMap = BitMask(ParseNumber(aValue)); + ChipLogDetail(Support, "Using FeatureMap 0x%04x", sFeatureMap.Raw()); + break; + default: + ChipLogError(Support, "%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName); + retval = false; + break; + } + + return (retval); +} + int main(int argc, char * argv[]) { - if (ChipLinuxAppInit(argc, argv) != 0) + if (ChipLinuxAppInit(argc, argv, &sCmdLineOptions) != 0) { return -1; } diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index b92d76e613e618..37bf2495f08736 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -90,6 +90,9 @@ #if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER #include #endif +#if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_ENERGY_MANAGEMENT_TRIGGER +#include +#endif #include #include @@ -553,6 +556,10 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) static EnergyReportingTestEventTriggerHandler sEnergyReportingTestEventTriggerHandler; sTestEventTriggerDelegate.AddHandler(&sEnergyReportingTestEventTriggerHandler); #endif +#if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_ENERGY_MANAGEMENT_TRIGGER + static DeviceEnergyManagementTestEventTriggerHandler sDeviceEnergyManagementTestEventTriggerHandler; + sTestEventTriggerDelegate.AddHandler(&sDeviceEnergyManagementTestEventTriggerHandler); +#endif initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index 4641eae6446e04..cd79d2b42e3273 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -24,6 +24,7 @@ declare_args() { chip_enable_boolean_state_configuration_trigger = false chip_enable_energy_evse_trigger = false chip_enable_energy_reporting_trigger = false + chip_enable_device_energy_management_trigger = false } config("app-main-config") { @@ -52,6 +53,10 @@ source_set("energy-reporting-test-event-trigger") { sources = [ "${chip_root}/src/app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerHandler.h" ] } +source_set("device-energy-management-test-event-trigger") { + sources = [ "${chip_root}/src/app/clusters/device-energy-management-server/DeviceEnergyManagementTestEventTriggerHandler.h" ] +} + source_set("app-main") { defines = [ "ENABLE_TRACING=${matter_enable_tracing_support}" ] sources = [ @@ -75,6 +80,7 @@ source_set("app-main") { public_deps = [ ":boolean-state-configuration-test-event-trigger", + ":device-energy-management-test-event-trigger", ":energy-evse-test-event-trigger", ":energy-reporting-test-event-trigger", ":smco-test-event-trigger", @@ -117,6 +123,7 @@ source_set("app-main") { "CHIP_DEVICE_CONFIG_ENABLE_BOOLEAN_STATE_CONFIGURATION_TRIGGER=${chip_enable_boolean_state_configuration_trigger}", "CHIP_DEVICE_CONFIG_ENABLE_ENERGY_EVSE_TRIGGER=${chip_enable_energy_evse_trigger}", "CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER=${chip_enable_energy_reporting_trigger}", + "CHIP_DEVICE_CONFIG_ENABLE_DEVICE_ENERGY_MANAGEMENT_TRIGGER=${chip_enable_device_energy_management_trigger}", ] public_configs = [ ":app-main-config" ] diff --git a/examples/shell/shell_common/BUILD.gn b/examples/shell/shell_common/BUILD.gn index cb098a64598a1b..0e318ccb31a5ca 100644 --- a/examples/shell/shell_common/BUILD.gn +++ b/examples/shell/shell_common/BUILD.gn @@ -72,14 +72,17 @@ static_library("shell_common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/ElectricalPowerMeasurementDelegate.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyTimeUtils.cpp", ] include_dirs = [ "${chip_root}/examples/all-clusters-app/all-clusters-common/include", "${chip_root}/examples/energy-management-app/energy-management-common/include", + "${chip_root}/src/app/clusters/device-energy-management-server", ] public_deps += diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index b436f46cb7cb1f..da75e616aa1510 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -386,6 +386,12 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/${cluster}.h", "${_app_root}/clusters/${cluster}/EnergyReportingTestEventTriggerHandler.h", ] + } else if (cluster == "device-energy-management-server") { + sources += [ + "${_app_root}/clusters/${cluster}/${cluster}.cpp", + "${_app_root}/clusters/${cluster}/${cluster}.h", + "${_app_root}/clusters/${cluster}/DeviceEnergyManagementTestEventTriggerHandler.h", + ] } else if (cluster == "thread-network-diagnostics-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp", diff --git a/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp b/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp index dc6e2a44de618a..fa913bc900a065 100644 --- a/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp +++ b/src/app/clusters/device-energy-management-server/device-energy-management-server.cpp @@ -582,7 +582,7 @@ void Instance::HandlePauseRequest(HandlerContext & ctx, const Commands::PauseReq if (!forecast.Value().slots[activeSlotNumber].slotIsPausable.Value()) { ChipLogError(Zcl, "DEM: activeSlotNumber %d is NOT pausable.", activeSlotNumber); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); return; } @@ -607,6 +607,7 @@ void Instance::HandlePauseRequest(HandlerContext & ctx, const Commands::PauseReq if (status != Status::Success) { ChipLogError(Zcl, "DEM: PauseRequest(%ld) FAILURE", static_cast(duration)); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); return; } } @@ -623,7 +624,7 @@ void Instance::HandleResumeRequest(HandlerContext & ctx, const Commands::ResumeR if (ESAStateEnum::kPaused != mDelegate.GetESAState()) { ChipLogError(Zcl, "DEM: ESAState not Paused."); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidInState); return; } @@ -678,7 +679,7 @@ void Instance::HandleModifyForecastRequest(HandlerContext & ctx, const Commands: if (slotAdjustment.slotIndex > forecast.Value().slots.size()) { ChipLogError(Zcl, "DEM: Bad slot index %d", slotAdjustment.slotIndex); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); return; } @@ -726,6 +727,7 @@ void Instance::HandleModifyForecastRequest(HandlerContext & ctx, const Commands: if (status != Status::Success) { ChipLogError(Zcl, "DEM: ModifyForecastRequest FAILURE"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Failure); return; } } diff --git a/src/app/clusters/device-energy-management-server/device-energy-management-server.h b/src/app/clusters/device-energy-management-server/device-energy-management-server.h index b0d27b0b99edd7..c58e5c5a73743a 100644 --- a/src/app/clusters/device-energy-management-server/device-energy-management-server.h +++ b/src/app/clusters/device-energy-management-server/device-energy-management-server.h @@ -45,6 +45,9 @@ class Delegate * @brief Delegate should implement a handler to begin to adjust client power * consumption/generation to the level requested. * + * Note callers must call GetPowerAdjustmentCapability and ensure the return value is not null + * before calling PowerAdjustRequest. + * * @param power Milli-Watts the ESA SHALL use during the adjustment period. * @param duration The duration that the ESA SHALL maintain the requested power for. * @return Success if the adjustment is accepted; otherwise the command SHALL be rejected with appropriate error. @@ -160,25 +163,42 @@ class Delegate // ------------------------------------------------------------------ // Get attribute methods - virtual ESATypeEnum GetESAType() = 0; - virtual bool GetESACanGenerate() = 0; - virtual ESAStateEnum GetESAState() = 0; - virtual int64_t GetAbsMinPower() = 0; - virtual int64_t GetAbsMaxPower() = 0; - virtual DataModel::Nullable GetPowerAdjustmentCapability() = 0; - virtual DataModel::Nullable GetForecast() = 0; - virtual OptOutStateEnum GetOptOutState() = 0; + virtual ESATypeEnum GetESAType() = 0; + virtual bool GetESACanGenerate() = 0; + virtual ESAStateEnum GetESAState() = 0; + virtual int64_t GetAbsMinPower() = 0; + virtual int64_t GetAbsMaxPower() = 0; + virtual OptOutStateEnum GetOptOutState() = 0; + + /** + * @brief Returns the current PowerAdjustCapability object + * + * The reference returned from GetPowerAdjustmentCapability() is only valid until the next Matter event + * is processed. Callers must not hold on to that reference for any asynchronous processing. + * + * Once another Matter event has had a chance to run, the memory associated with the + * PowerAdjustCapabilityStruct is likely to change or be re-allocated, so would become invalid. + * + * @return The current PowerAdjustCapability object + */ + virtual const DataModel::Nullable & GetPowerAdjustmentCapability() = 0; + + /** + * @brief Returns the current Forecast object + * + * The reference returned from GetForecast() is only valid until the next Matter event + * is processed. Callers must not hold on to that reference for any asynchronous processing. + * + * Once another Matter event has had a chance to run, the memory associated with the + * ForecastStruct is likely to change or be re-allocated, so would become invalid. + * + * @return The current Forecast object + */ + virtual const DataModel::Nullable & GetForecast() = 0; // ------------------------------------------------------------------ // Set attribute methods - virtual CHIP_ERROR SetESAType(ESATypeEnum) = 0; - virtual CHIP_ERROR SetESACanGenerate(bool) = 0; - virtual CHIP_ERROR SetESAState(ESAStateEnum) = 0; - virtual CHIP_ERROR SetAbsMinPower(int64_t) = 0; - virtual CHIP_ERROR SetAbsMaxPower(int64_t) = 0; - virtual CHIP_ERROR SetPowerAdjustmentCapability(DataModel::Nullable) = 0; - virtual CHIP_ERROR SetForecast(DataModel::Nullable) = 0; - virtual CHIP_ERROR SetOptOutState(OptOutStateEnum) = 0; + virtual CHIP_ERROR SetESAState(ESAStateEnum) = 0; protected: EndpointId mEndpointId = 0; diff --git a/src/python_testing/TC_DEM_2_2.py b/src/python_testing/TC_DEM_2_2.py new file mode 100644 index 00000000000000..dc81cbcc0aa9d2 --- /dev/null +++ b/src/python_testing/TC_DEM_2_2.py @@ -0,0 +1,367 @@ +# +# 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. +# pylint: disable=invalid-name + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0x01 +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +"""Define Matter test case TC_DEM_2_2.""" + + +import datetime +import logging +import sys +import time + +import chip.clusters as Clusters +from chip.interaction_model import Status +from matter_testing_support import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts +from TC_DEMTestBase import DEMTestBase + +logger = logging.getLogger(__name__) + + +class TC_DEM_2_2(MatterBaseTest, DEMTestBase): + """Implementation of test case TC_DEM_2_2.""" + + def desc_TC_DEM_2_2(self) -> str: + """Return a description of this test.""" + return "4.1.3. [TC-DEM-2.2] Power Adjustment feature functionality with DUT as Server" + + def pics_TC_DEM_2_2(self): + """Return the PICS definitions associated with this test.""" + pics = [ + "DEM.S.F00", # Depends on Feature 00 (PowerAdjustment) + ] + return pics + + def steps_TC_DEM_2_2(self) -> list[TestStep]: + """Execute the test steps.""" + steps = [ + TestStep("1", "Commissioning, already done", + is_commissioning=True), + TestStep("2", "TH reads TestEventTriggersEnabled attribute from General Diagnostics Cluster.", + "Verify that TestEventTriggersEnabled attribute has a value of 1 (True)"), + TestStep("3", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Power Adjustment Test Event", + "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("3a", "TH reads ESAState attribute.", + "Verify value is 0x01 (Online)"), + TestStep("3b", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=NoAdjustment. Note value for later. Determine the OverallMaxPower and OverallMaxDuration as the largest MaxPower and MaxDuration of the PowerAdjustStructs returned, and similarly the OverallMinPower and OverallMinDuration as the smallest of the MinPower and MinDuration values."), + TestStep("3c", "TH reads OptOutState attribute.", + "Verify value is 0x00 (NoOptOut)"), + TestStep("4", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", + "Verify DUT responds with status SUCCESS(0x00) and Event DEM.S.E00(PowerAdjustStart) sent"), + TestStep("4a", "TH reads ESAState attribute.", + "Verify value is 0x04 (PowerAdjustActive)"), + TestStep("4b", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=LocalOptimizationAdjustment."), + TestStep("5", "TH sends CancelPowerAdjustRequest.", + "Verify DUT responds with status SUCCESS(0x00) and Event DEM.S.E01(PowerAdjustEnd) sent with Cause=Cancelled"), + TestStep("5a", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=NoAdjustment."), + TestStep("5b", "TH reads ESAState attribute.", + "Verify value is 0x01 (Online)"), + TestStep("6", "TH sends CancelPowerAdjustRequest.", + "Verify DUT responds with status INVALID_IN_STATE(0xcb)"), + TestStep("7", "TH sends PowerAdjustRequest with Power=OverallMaxPower+1 Duration=OverallMinDuration Cause=LocalOptimization.", + "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), + TestStep("8", "TH sends PowerAdjustRequest with Power=OverallMinPower Duration=OverallMaxDuration+1 Cause=LocalOptimization.", + "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), + TestStep("9", "TH sends PowerAdjustRequest with Power=OverallMinPower-1 Duration=OverallMaxDuration Cause=LocalOptimization.", + "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), + TestStep("10", "TH sends PowerAdjustRequest with Power=OverallMaxPower Duration=OverallMinDuration-1 Cause=LocalOptimization.", + "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), + TestStep("11", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", + "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E00(PowerAdjustStart) sent"), + TestStep("11a", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=LocalOptimizationAdjustment."), + TestStep("12", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=GridOptimization.", + "Verify DUT responds with status SUCCESS(0x00) and no event sent"), + TestStep("12a", "TH reads ESAState attribute.", + "Verify value is 0x04 (PowerAdjustActive)"), + TestStep("12b", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=GridOptimizationAdjustment."), + TestStep("13", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Local Optimization Test Event.", + "Verify DUT responds with status SUCCESS(0x00) and no event sent"), + TestStep("13a", "TH reads ESAState attribute.", + "Verify value is 0x04 (PowerAdjustActive)"), + TestStep("13b", "TH reads OptOutState attribute.", + "Verify value is 0x02 (LocalOptOut)"), + TestStep("14", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", + "Verify DUT responds with status CONSTRAINT_ERROR(0x87)"), + TestStep("15", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Grid Optimization Test Event.", + "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E01(PowerAdjustEnd) sent with Cause=UserOptOut, Duration= approx time from step 11 to step 15, EnergyUse= a valid value"), + TestStep("15a", "TH reads ESAState attribute.", + "Verify value is 0x01 (Online)"), + TestStep("15b", "TH reads OptOutState attribute.", + "Verify value is 0x03 (OptOut)"), + TestStep("15c", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=NoAdjustment."), + TestStep("16", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for User Opt-out Test Event Clear", + "Verify DUT responds with status SUCCESS(0x00)"), + TestStep("16a", "TH reads ESAState attribute.", + "Verify value is 0x01 (Online)"), + TestStep("16b", "TH reads OptOutState attribute.", + "Verify value is 0x00 (NoOptOut)"), + TestStep("17", "TH sends PowerAdjustRequest with Power=PowerAdjustmentCapability[0].MaxPower, Duration=PowerAdjustmentCapability[0].MinDuration, Cause=LocalOptimization.", + "Verify DUT responds with status SUCCESS(0x00) and event DEM.S.E00(PowerAdjustStart) sent"), + TestStep("17a", "TH reads ESAState attribute.", + "Verify value is 0x04 (PowerAdjustActive)"), + TestStep("17b", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=LocalOptimizationAdjustment."), + TestStep("18", "Wait 10 seconds.", + "Event DEM.S.E01(PowerAdjustEnd) sent with Cause=NormalCompletion, Duration=10s, EnergyUse= a valid value"), + TestStep("18a", "TH reads ESAState attribute.", + "Verify value is 0x01 (Online)"), + TestStep("18b", "TH reads PowerAdjustmentCapability attribute.", + "Value has to include Cause=NoAdjustment."), + TestStep("19", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.DEM.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.DEM.TEST_EVENT_TRIGGER for Power Adjustment Test Event Clear", + "Verify DUT responds with status SUCCESS(0x00)"), + ] + + return steps + + @async_test_body + async def test_TC_DEM_2_2(self): + # pylint: disable=too-many-locals, too-many-statements + """Run the test steps.""" + min_duration = 10 + max_duration = 60 + + self.step("1") + # Commission DUT - already done + + # Subscribe to Events and when they are sent push them to a queue for checking later + events_callback = EventChangeCallback(Clusters.DeviceEnergyManagement) + await events_callback.start(self.default_controller, + self.dut_node_id, + self.matter_test_config.endpoint) + + self.step("2") + await self.check_test_event_triggers_enabled() + + self.step("3") + await self.send_test_event_trigger_power_adjustment() + + self.step("3a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) + + self.step("3b") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) + logging.info(powerAdjustCapabilityStruct) + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) + + # we should expect powerAdjustCapabilityStruct to have multiple entries with different max powers, min powers, max and min durations + min_power = sys.maxsize + max_power = 0 + min_duration = sys.maxsize + max_duration = 0 + + for entry in powerAdjustCapabilityStruct.powerAdjustCapability: + min_power = min(min_power, entry.minPower) + max_power = max(max_power, entry.maxPower) + min_duration = min(min_duration, entry.minDuration) + max_duration = max(max_duration, entry.maxDuration) + + result = f"min_power {min_power} max_power {max_power} min_duration {min_duration} max_duration {max_duration}" + logging.info(result) + + self.step("3c") + await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) + + self.step("4") + await self.send_power_adjustment_command(power=max_power, + duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) + + event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart) + + self.step("4a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) + + self.step("4b") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment) + + self.step("5") + await self.send_cancel_power_adjustment_command() + event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustEnd) + asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kCancelled) + + self.step("5a") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) + + self.step("5b") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) + + self.step("6") + await self.send_cancel_power_adjustment_command(expected_status=Status.InvalidInState) + + self.step("7") + await self.send_power_adjustment_command(power=max_power + 1, + duration=min_duration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, + expected_status=Status.ConstraintError) + + self.step("8") + await self.send_power_adjustment_command(power=min_power, + duration=max_duration + 1, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, + expected_status=Status.ConstraintError) + + self.step("9") + await self.send_power_adjustment_command(power=min_power - 1, + duration=max_duration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, + expected_status=Status.ConstraintError) + + self.step("10") + await self.send_power_adjustment_command(power=max_power, + duration=min_duration - 1, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, + expected_status=Status.ConstraintError) + + self.step("11") + start = datetime.datetime.now() + await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, + duration=min_duration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization) + + event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart) + + self.step("11a") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment) + + self.step("12") + await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, + duration=min_duration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization) + + # Wait 5 seconds for an event not to be reported + events_callback.wait_for_event_expect_no_report(5) + + self.step("12a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) + + self.step("12b") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1) + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kGridOptimizationAdjustment) + + self.step("13") + await self.send_test_event_trigger_user_opt_out_local() + + self.step("13a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) + + self.step("13b") + await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kLocalOptOut) + + self.step("14") + await self.send_power_adjustment_command(power=max_power, + duration=max_duration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, + expected_status=Status.ConstraintError) + + self.step("15") + await self.send_test_event_trigger_user_opt_out_grid() + event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustEnd) + asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kUserOptOut) + + # Allow 3s error margin as the CI build system can run out of CPU time + elapsed = datetime.datetime.now() - start + asserts.assert_less_equal(abs(elapsed.seconds - event_data.duration), 3) + asserts.assert_greater_equal(event_data.energyUse, 0) + + self.step("15a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) + + self.step("15b") + await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kOptOut) + + self.step("15c") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) + + self.step("16") + await self.send_test_event_trigger_user_opt_out_clear_all() + + self.step("16a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) + + self.step("16b") + await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut) + + self.step("17") + await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower, + duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration, + cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization, + expected_status=Status.Success) + event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart) + + self.step("17a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kPowerAdjustActive) + + self.step("17b") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment) + + self.step("18") + time.sleep(10) + + event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustEnd) + asserts.assert_equal(event_data.duration, 10) + asserts.assert_equal(event_data.cause, Clusters.DeviceEnergyManagement.Enums.CauseEnum.kNormalCompletion) + asserts.assert_greater(event_data.energyUse, 0) + + self.step("18a") + await self.check_dem_attribute("ESAState", Clusters.DeviceEnergyManagement.Enums.ESAStateEnum.kOnline) + + self.step("18b") + powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability") + asserts.assert_equal(powerAdjustCapabilityStruct.cause, + Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment) + + self.step("19") + await self.send_test_event_trigger_power_adjustment_clear() + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 11b1dfb01c0760..0fe12e777bc866 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -256,11 +256,11 @@ def __call__(self, res: EventReadResult, transaction: SubscriptionTransaction): f'Got subscription report for event on cluster {self._expected_cluster}: {res.Data}') self._q.put(res) - def wait_for_event_report(self, expected_event: ClusterObjects.ClusterEvent, timeout: int = 10): - """This function allows a test script to block waiting for the specific event to arrive with a timeout. - It returns the event data so that the values can be checked.""" + def wait_for_event_report(self, expected_event: ClusterObjects.ClusterEvent, timeoutS: int = 10): + """This function allows a test script to block waiting for the specific event to arrive with a timeout + (specified in seconds). It returns the event data so that the values can be checked.""" try: - res = self._q.get(block=True, timeout=timeout) + res = self._q.get(block=True, timeout=timeoutS) except queue.Empty: asserts.fail("Failed to receive a report for the event {}".format(expected_event)) @@ -268,6 +268,16 @@ def wait_for_event_report(self, expected_event: ClusterObjects.ClusterEvent, tim asserts.assert_equal(res.Header.EventId, expected_event.event_id, "Expected event ID not found in event report") return res.Data + def wait_for_event_expect_no_report(self, timeoutS: int = 10): + """This function succceeds/returns if an event does not arrive within the timeout specified in seconds. + If an event does arrive, an assert is called.""" + try: + res = self._q.get(block=True, timeout=timeoutS) + except queue.Empty: + return + + asserts.fail(f"Event reported when not expected {res}") + @property def event_queue(self) -> queue.Queue: return self._q From 20c251ba0c2fe6560b580b39964a6f74bbce4f29 Mon Sep 17 00:00:00 2001 From: PeterC1965 <101805108+PeterC1965@users.noreply.github.com> Date: Fri, 26 Jul 2024 02:00:03 +0100 Subject: [PATCH 12/17] Add water heater mode to sdk and all-clusters-app (#34351) * Add water heater mode cluster * Get all-clusters-app building with water-heater-mode * Restyled by clang-format * Added call to WaterHeaterMode::Shutdown() to fix IntrusiveList not being freed at exit. * Added missing #include "water-heater-mode.h" to main-common.cpp * Regenerated files * Update following review comments from Andrei Litvin * Fix compilation error * Restyled by clang-format * Update after review comment from Boris * WaterHeaterMode moved to future section * Update examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h Co-authored-by: Andrei Litvin * Address final set of review comments from Andrei --------- Co-authored-by: Restyled.io Co-authored-by: jamesharrow <93921463+jamesharrow@users.noreply.github.com> Co-authored-by: James Harrow Co-authored-by: Andrei Litvin --- .../all-clusters-app.matter | 66 ++++++ .../all-clusters-common/all-clusters-app.zap | 188 ++++++++++++++++++ .../include/water-heater-mode.h | 73 +++++++ .../src/water-heater-mode.cpp | 105 ++++++++++ examples/all-clusters-app/linux/BUILD.gn | 1 + .../all-clusters-app/linux/main-common.cpp | 2 + src/app/common/templates/config-data.yaml | 2 + src/app/util/util.cpp | 1 + src/app/zap_cluster_list.json | 2 + .../data_model/controller-clusters.zap | 60 ++++++ .../python/chip/clusters/Objects.py | 10 +- .../app-common/zap-generated/callback.h | 6 - .../zap-generated/cluster-enums-check.h | 14 -- .../app-common/zap-generated/cluster-enums.h | 10 +- 14 files changed, 510 insertions(+), 30 deletions(-) create mode 100644 examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h create mode 100644 examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index b8855227a52db1..4313908d4fcdcb 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -4582,6 +4582,56 @@ cluster EnergyEvseMode = 157 { command ChangeToMode(ChangeToModeRequest): ChangeToModeResponse = 0; } +/** Attributes and commands for selecting a mode from a list of supported options. */ +cluster WaterHeaterMode = 158 { + revision 1; + + enum ModeTag : enum16 { + kOff = 16384; + kManual = 16385; + kTimed = 16386; + } + + bitmap Feature : bitmap32 { + kOnOff = 0x1; + } + + struct ModeTagStruct { + optional vendor_id mfgCode = 0; + enum16 value = 1; + } + + struct ModeOptionStruct { + char_string<64> label = 0; + int8u mode = 1; + ModeTagStruct modeTags[] = 2; + } + + readonly attribute ModeOptionStruct supportedModes[] = 0; + readonly attribute int8u currentMode = 1; + attribute optional nullable int8u startUpMode = 2; + attribute optional nullable int8u onMode = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ChangeToModeRequest { + int8u newMode = 0; + } + + response struct ChangeToModeResponse = 1 { + enum8 status = 0; + optional char_string statusText = 1; + } + + /** This command is used to change device modes. + On receipt of this command the device SHALL respond with a ChangeToModeResponse command. */ + command ChangeToMode(ChangeToModeRequest): ChangeToModeResponse = 0; +} + /** Attributes and commands for selecting a mode from a list of supported options. */ provisional cluster DeviceEnergyManagementMode = 159 { revision 1; @@ -8479,6 +8529,22 @@ endpoint 1 { handle command ChangeToModeResponse; } + server cluster WaterHeaterMode { + callback attribute supportedModes; + callback attribute currentMode; + ram attribute startUpMode; + ram attribute onMode; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + + handle command ChangeToMode; + handle command ChangeToModeResponse; + } + server cluster DeviceEnergyManagementMode { callback attribute supportedModes; callback attribute currentMode; diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 6491378c9e83d7..3c9dcb094f8eb4 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -14745,6 +14745,194 @@ } ] }, + { + "name": "Water Heater Mode", + "code": 158, + "mfgCode": null, + "define": "WATER_HEATER_MODE_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ChangeToMode", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ChangeToModeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedModes", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentMode", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartUpMode", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnMode", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Device Energy Management Mode", "code": 159, diff --git a/examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h b/examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h new file mode 100644 index 00000000000000..9f3515094ed255 --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/include/water-heater-mode.h @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2023 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { + +namespace WaterHeaterMode { + +constexpr uint8_t kModeOff = 0; +constexpr uint8_t kModeManual = 1; +constexpr uint8_t kModeTimed = 2; + +/// This is an application level delegate to handle WaterHeaterMode commands according to the specific business logic. +class ExampleWaterHeaterModeDelegate : public ModeBase::Delegate +{ +private: + using ModeTagStructType = detail::Structs::ModeTagStruct::Type; + ModeTagStructType modeTagsOff[1] = { { .value = to_underlying(ModeTag::kOff) } }; + ModeTagStructType modeTagsManual[1] = { { .value = to_underlying(ModeTag::kManual) } }; + ModeTagStructType modeTagsTimed[1] = { { .value = to_underlying(ModeTag::kTimed) } }; + + const detail::Structs::ModeOptionStruct::Type kModeOptions[3] = { + detail::Structs::ModeOptionStruct::Type{ + .label = "Off"_span, .mode = kModeOff, .modeTags = DataModel::List(modeTagsOff) }, + detail::Structs::ModeOptionStruct::Type{ + .label = "Manual"_span, .mode = kModeManual, .modeTags = DataModel::List(modeTagsManual) }, + detail::Structs::ModeOptionStruct::Type{ + .label = "Timed"_span, .mode = kModeTimed, .modeTags = DataModel::List(modeTagsTimed) } + }; + + CHIP_ERROR Init() override; + void HandleChangeToMode(uint8_t mode, ModeBase::Commands::ChangeToModeResponse::Type & response) override; + + CHIP_ERROR GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label) override; + CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) override; + CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List & tags) override; + +public: + ~ExampleWaterHeaterModeDelegate() override = default; +}; + +ModeBase::Instance * Instance(); + +void Shutdown(); + +} // namespace WaterHeaterMode + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp b/examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp new file mode 100644 index 00000000000000..9c4121fb70d668 --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp @@ -0,0 +1,105 @@ +/* + * + * Copyright (c) 2023 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 +#include + +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::WaterHeaterMode; +using chip::Protocols::InteractionModel::Status; +template +using List = chip::app::DataModel::List; +using ModeTagStructType = chip::app::Clusters::detail::Structs::ModeTagStruct::Type; + +static ExampleWaterHeaterModeDelegate * gWaterHeaterModeDelegate = nullptr; +static ModeBase::Instance * gWaterHeaterModeInstance = nullptr; + +CHIP_ERROR ExampleWaterHeaterModeDelegate::Init() +{ + return CHIP_NO_ERROR; +} + +// todo refactor code by making a parent class for all ModeInstance classes to reduce flash usage. +void ExampleWaterHeaterModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response) +{ + response.status = to_underlying(ModeBase::StatusCode::kSuccess); +} + +CHIP_ERROR ExampleWaterHeaterModeDelegate::GetModeLabelByIndex(uint8_t modeIndex, chip::MutableCharSpan & label) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + return chip::CopyCharSpanToMutableCharSpan(kModeOptions[modeIndex].label, label); +} + +CHIP_ERROR ExampleWaterHeaterModeDelegate::GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + value = kModeOptions[modeIndex].mode; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ExampleWaterHeaterModeDelegate::GetModeTagsByIndex(uint8_t modeIndex, List & tags) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + + if (tags.size() < kModeOptions[modeIndex].modeTags.size()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + std::copy(kModeOptions[modeIndex].modeTags.begin(), kModeOptions[modeIndex].modeTags.end(), tags.begin()); + tags.reduce_size(kModeOptions[modeIndex].modeTags.size()); + + return CHIP_NO_ERROR; +} + +ModeBase::Instance * WaterHeaterMode::Instance() +{ + return gWaterHeaterModeInstance; +} + +void WaterHeaterMode::Shutdown() +{ + if (gWaterHeaterModeInstance != nullptr) + { + delete gWaterHeaterModeInstance; + gWaterHeaterModeInstance = nullptr; + } + if (gWaterHeaterModeDelegate != nullptr) + { + delete gWaterHeaterModeDelegate; + gWaterHeaterModeDelegate = nullptr; + } +} + +void emberAfWaterHeaterModeClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(gWaterHeaterModeDelegate == nullptr && gWaterHeaterModeInstance == nullptr); + gWaterHeaterModeDelegate = new WaterHeaterMode::ExampleWaterHeaterModeDelegate; + gWaterHeaterModeInstance = + new ModeBase::Instance(gWaterHeaterModeDelegate, endpointId, WaterHeaterMode::Id, chip::to_underlying(Feature::kOnOff)); + gWaterHeaterModeInstance->Init(); +} diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index e71574ce4db5ac..ca1149b25e7891 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -57,6 +57,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/tcc-mode.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/water-heater-mode.cpp", "${chip_root}/examples/all-clusters-app/linux/diagnostic-logs-provider-delegate-impl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementManager.cpp", diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index 73af031ecbdb5d..1d1799ece3581b 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -37,6 +37,7 @@ #include "rvc-modes.h" #include "rvc-operational-state-delegate-impl.h" #include "tcc-mode.h" +#include "water-heater-mode.h" #include #include #include @@ -259,6 +260,7 @@ void ApplicationShutdown() Clusters::DeviceEnergyManagementMode::Shutdown(); Clusters::EnergyEvseMode::Shutdown(); + Clusters::WaterHeaterMode::Shutdown(); if (sChipNamedPipeCommands.Stop() != CHIP_NO_ERROR) { diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index fd060149c8ff20..a3ae2dc621fd03 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -13,6 +13,7 @@ EnumsNotUsedAsTypeInXML: - "RvcOperationalState::OperationalStateEnum" - "RvcOperationalState::ErrorStateEnum" - "EnergyEvseMode::ModeTag" + - "WaterHeaterMode::ModeTag" - "DeviceEnergyManagementMode::ModeTag" CommandHandlerInterfaceOnlyClusters: @@ -42,6 +43,7 @@ CommandHandlerInterfaceOnlyClusters: - Electrical Energy Measurement - Wi-Fi Network Management - Thread Network Directory + - Water Heater Mode # We need a more configurable way of deciding which clusters have which init functions.... # See https://github.com/project-chip/connectedhomeip/issues/4369 diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index b485e7c5dfb4cb..6a23c48a43f6bf 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -139,6 +139,7 @@ void MatterEnergyEvseModePluginServerInitCallback() {} void MatterPowerTopologyPluginServerInitCallback() {} void MatterElectricalEnergyMeasurementPluginServerInitCallback() {} void MatterElectricalPowerMeasurementPluginServerInitCallback() {} +void MatterWaterHeaterModePluginServerInitCallback() {} bool emberAfContainsAttribute(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId) { diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index 00bcb55adb90a7..c17a59678697a8 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -131,6 +131,7 @@ "WAKE_ON_LAN_CLUSTER": [], "LAUNDRY_WASHER_CONTROLS_CLUSTER": [], "LAUNDRY_DRYER_CONTROLS_CLUSTER": [], + "WATER_HEATER_MODE_CLUSTER": [], "WIFI_NETWORK_DIAGNOSTICS_CLUSTER": [], "WINDOW_COVERING_CLUSTER": [], "ZLL_COMMISSIONING_CLUSTER": [] @@ -314,6 +315,7 @@ "WIFI_NETWORK_DIAGNOSTICS_CLUSTER": ["wifi-network-diagnostics-server"], "WIFI_NETWORK_MANAGEMENT_CLUSTER": ["wifi-network-management-server"], "WINDOW_COVERING_CLUSTER": ["window-covering-server"], + "WATER_HEATER_MODE_CLUSTER": ["mode-base-server"], "ZLL_COMMISSIONING_CLUSTER": [] } } diff --git a/src/controller/data_model/controller-clusters.zap b/src/controller/data_model/controller-clusters.zap index 97d960bb7f4d30..71f77c8d6159b5 100644 --- a/src/controller/data_model/controller-clusters.zap +++ b/src/controller/data_model/controller-clusters.zap @@ -3394,6 +3394,66 @@ } ] }, + { + "name": "Water Heater Mode", + "code": 158, + "mfgCode": null, + "define": "WATER_HEATER_MODE_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "ChangeToMode", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ChangeToModeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Device Energy Management Mode", "code": 159, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 13c6fe3d9f4dab..654a6d292a6910 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -26894,11 +26894,11 @@ class ModeTag(MatterIntEnum): kOff = 0x4000 kManual = 0x4001 kTimed = 0x4002 - # All received enum values that are not listed above will be mapped - # to kUnknownEnumValue. This is a helper enum value that should only - # be used by code to process how it handles receiving and unknown - # enum value. This specific should never be transmitted. - kUnknownEnumValue = 0, + # kUnknownEnumValue intentionally not defined. This enum never goes + # through DataModel::Decode, likely because it is a part of a derived + # cluster. As a result having kUnknownEnumValue in this enum is error + # prone, and was removed. See + # src/app/common/templates/config-data.yaml. class Bitmaps: class Feature(IntFlag): diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index bb2d5a3f3dd501..03f0b7bbef238e 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -6071,12 +6071,6 @@ bool emberAfMessagesClusterPresentMessagesRequestCallback( bool emberAfMessagesClusterCancelMessagesRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::Messages::Commands::CancelMessagesRequest::DecodableType & commandData); -/** - * @brief Water Heater Mode Cluster ChangeToMode Command callback (from client) - */ -bool emberAfWaterHeaterModeClusterChangeToModeCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WaterHeaterMode::Commands::ChangeToMode::DecodableType & commandData); /** * @brief Door Lock Cluster LockDoor Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index 13951c0ff2bc00..0304b683406b8b 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -1895,20 +1895,6 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(EnergyPreference::Energ } } -static auto __attribute__((unused)) EnsureKnownEnumValue(WaterHeaterMode::ModeTag val) -{ - using EnumType = WaterHeaterMode::ModeTag; - switch (val) - { - case EnumType::kOff: - case EnumType::kManual: - case EnumType::kTimed: - return val; - default: - return EnumType::kUnknownEnumValue; - } -} - static auto __attribute__((unused)) EnsureKnownEnumValue(DoorLock::AlarmCodeEnum val) { using EnumType = DoorLock::AlarmCodeEnum; diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index fd0f8d24d26dc6..612637d3af1776 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -2823,11 +2823,11 @@ enum class ModeTag : uint16_t kOff = 0x4000, kManual = 0x4001, kTimed = 0x4002, - // All received enum values that are not listed above will be mapped - // to kUnknownEnumValue. This is a helper enum value that should only - // be used by code to process how it handles receiving and unknown - // enum value. This specific should never be transmitted. - kUnknownEnumValue = 0, + // kUnknownEnumValue intentionally not defined. This enum never goes + // through DataModel::Decode, likely because it is a part of a derived + // cluster. As a result having kUnknownEnumValue in this enum is error + // prone, and was removed. See + // src/app/common/templates/config-data.yaml. }; // Bitmap for Feature From 10d653ddf42665df5a8bda8cb9ef61bcc29584dd Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:52:54 -0400 Subject: [PATCH 13/17] [OO] Scenes Integration Tests (#34447) * Added test for scenes integration in onoff cluster * Made onoff and scenes behaviors independant in scenes interaction * Added the test to the CI --- .../clusters/level-control/level-control.cpp | 9 +- .../clusters/on-off-server/on-off-server.cpp | 15 +- .../suites/certification/Test_TC_OO_2_7.yaml | 269 ++++++++++++++++++ src/app/tests/suites/ciTests.json | 7 +- 4 files changed, 280 insertions(+), 20 deletions(-) create mode 100644 src/app/tests/suites/certification/Test_TC_OO_2_7.yaml diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index 814436c39e179a..738a7b10ed0ffb 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -256,12 +256,9 @@ class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl if (!NumericAttributeTraits::IsNullValue(level)) { - CommandId command = LevelControlHasFeature(endpoint, LevelControl::Feature::kOnOff) ? Commands::MoveToLevelWithOnOff::Id - : Commands::MoveToLevel::Id; - - moveToLevelHandler(endpoint, command, level, DataModel::MakeNullable(static_cast(timeMs / 100)), - chip::Optional>(), chip::Optional>(), - INVALID_STORED_LEVEL); + moveToLevelHandler( + endpoint, Commands::MoveToLevel::Id, level, DataModel::MakeNullable(static_cast(timeMs / 100)), + chip::Optional>(1), chip::Optional>(1), INVALID_STORED_LEVEL); } return CHIP_NO_ERROR; diff --git a/src/app/clusters/on-off-server/on-off-server.cpp b/src/app/clusters/on-off-server/on-off-server.cpp index 726da2d29f7c4d..98dfaf9da02c3e 100644 --- a/src/app/clusters/on-off-server/on-off-server.cpp +++ b/src/app/clusters/on-off-server/on-off-server.cpp @@ -213,19 +213,8 @@ class DefaultOnOffSceneHandler : public scenes::DefaultSceneHandlerImpl return err; } - // This handler assumes it is being used with the default handler for the level control. Therefore if the level control - // cluster with on off feature is present on the endpoint and the level control handler is registered, it assumes this - // handler will take action on the on-off state. This assumes the level control attributes were also saved in the scene. - // This is to prevent a behavior where the on off state is set by this handler, and then the level control handler or vice - // versa. -#ifdef MATTER_DM_PLUGIN_LEVEL_CONTROL - if (!(LevelControlWithOnOffFeaturePresent(endpoint) && - ScenesManagement::ScenesServer::Instance().IsHandlerRegistered(endpoint, LevelControlServer::GetSceneHandler()))) -#endif - { - VerifyOrReturnError(mTransitionTimeInterface.sceneEventControl(endpoint) != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - OnOffServer::Instance().scheduleTimerCallbackMs(mTransitionTimeInterface.sceneEventControl(endpoint), timeMs); - } + VerifyOrReturnError(mTransitionTimeInterface.sceneEventControl(endpoint) != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + OnOffServer::Instance().scheduleTimerCallbackMs(mTransitionTimeInterface.sceneEventControl(endpoint), timeMs); return CHIP_NO_ERROR; } diff --git a/src/app/tests/suites/certification/Test_TC_OO_2_7.yaml b/src/app/tests/suites/certification/Test_TC_OO_2_7.yaml new file mode 100644 index 00000000000000..19183ba79aff8d --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_OO_2_7.yaml @@ -0,0 +1,269 @@ +# Copyright (c) 2024 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. + +name: 4.2.4. [TC-OO-2.7] Scenes Management Cluster Interaction (DUT as Server) + +PICS: + - OO.S + - S.S + +config: + nodeId: 0x12344321 + cluster: "Scenes Management" + endpoint: 1 + G1: + type: group_id + defaultValue: 0x0001 + +tests: + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: + "Step 0a :TH sends KeySetWrite command in the GroupKeyManagement + cluster to DUT using a key that is pre-installed on the TH. + GroupKeySet fields are as follows:" + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a1, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1110000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1110001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1110002, + } + + - label: + "Step 0b: TH binds GroupIds 0x0001 and 0x0002 with GroupKeySetID + 0x01a1 in the GroupKeyMap attribute list on GroupKeyManagement cluster + by writing the GroupKeyMap attribute with two entries as follows:" + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: [{ FabricIndex: 1, GroupId: G1, GroupKeySetID: 0x01a1 }] + + - label: "Step 0c: TH sends a RemoveAllGroups command to DUT." + cluster: "Groups" + endpoint: endpoint + command: "RemoveAllGroups" + + - label: + "Step 1a: TH sends a AddGroup command to DUT with the GroupID field + set to G1." + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: + "Step 1b: TH sends a RemoveAllScenes command to DUT with the GroupID + field set to G1." + command: "RemoveAllScenes" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - label: + "Step 1c: TH sends a GetSceneMembership command to DUT with the + GroupID field set to G1." + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneList" + value: [] + + - label: "Step 2a: TH sends Off command to DUT" + cluster: "On/Off" + command: "Off" + + - label: "Wait 1000ms" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: 1000 + + - label: "Step 2b: after a few seconds, TH reads OnOff attribute from DUT" + cluster: "On/Off" + command: "readAttribute" + attribute: "OnOff" + response: + value: 0 + + - label: + "Step 2b: TH sends a StoreScene command to DUT with the GroupID field + set to G1 and the SceneID field set to 0x01." + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + + - label: "Step 3: TH sends a AddScene command to DUT with the GroupID field + set to G1, the SceneID field set to 0x02, the TransitionTime field set + to 1000 (1s) and the ExtensionFieldSets set to: '[{ ClusterID: 0x0006, + AttributeValueList: [{ AttributeID: 0x0000, ValueUnsigned8: 0x01 }]}]' + " + command: "AddScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + - name: "TransitionTime" + value: 1000 + - name: "SceneName" + value: "Scene1" + - name: "ExtensionFieldSets" + value: + [ + { + ClusterID: 0x0006, + AttributeValueList: + [{ AttributeID: 0x0000, ValueUnsigned8: 0x01 }], + }, + ] + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + + - label: + "Step 4a: TH sends a RecallScene command to DUT with the GroupID field + set to G1 and the SceneID field set to 0x02." + PICS: S.S.C05.Rsp + command: "RecallScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + + - label: "Wait 2000ms" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: 2000 + + - label: "Step 4b: after a few seconds, TH reads OnOff attribute from DUT" + cluster: "On/Off" + command: "readAttribute" + attribute: "OnOff" + response: + value: 1 + + - label: + "Step 5a: TH sends a RecallScene command to DUT with the GroupID field + set to G1 and the SceneID field set to 0x01." + PICS: S.S.C05.Rsp + command: "RecallScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + + - label: "Wait 1000ms" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: 1000 + + - label: "Step 5b: after a few seconds, TH reads OnOff attribute from DUT" + cluster: "On/Off" + command: "readAttribute" + attribute: "OnOff" + response: + value: 0 + + - label: + "Cleanup: TH sends a RemoveAllScenes command to DUT with the GroupID + field set to G1." + command: "RemoveAllScenes" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + + - label: "Cleanup: TH sends a RemoveAllGroups command to DUT." + cluster: "Groups" + endpoint: endpoint + command: "RemoveAllGroups" diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json index a77ecb9a3b2838..44cfcd1648a70d 100644 --- a/src/app/tests/suites/ciTests.json +++ b/src/app/tests/suites/ciTests.json @@ -144,7 +144,12 @@ "ModeSelect": [], "MultipleFabrics": [], "OTASoftwareUpdate": ["OTA_SuccessfulTransfer"], - "OnOff": ["Test_TC_OO_2_1", "Test_TC_OO_2_2", "Test_TC_OO_2_4"], + "OnOff": [ + "Test_TC_OO_2_1", + "Test_TC_OO_2_2", + "Test_TC_OO_2_4", + "Test_TC_OO_2_7" + ], "PowerSource": ["Test_TC_PS_2_1"], "PowerTopology": ["Test_TC_PWRTL_1_1"], "PressureMeasurement": ["Test_TC_PRS_2_1", "Test_TC_PRS_2_2"], From f53e2f9c4e4abf70af7b7c81f9ea41455d542168 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:06:21 -0400 Subject: [PATCH 14/17] [LC] LC Scenes Integration Tests (#34448) * Added test for scenes integration to Level control cluster * Removed interaction between OnOff and Level control from the test * Added new test to test plan * Update src/app/tests/suites/certification/Test_TC_LVL_9_1.yaml Co-authored-by: C Freeman * Added cleanup --------- Co-authored-by: C Freeman --- .../suites/certification/Test_TC_LVL_9_1.yaml | 264 ++++++++++++++++++ src/app/tests/suites/ciTests.json | 3 +- 2 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 src/app/tests/suites/certification/Test_TC_LVL_9_1.yaml diff --git a/src/app/tests/suites/certification/Test_TC_LVL_9_1.yaml b/src/app/tests/suites/certification/Test_TC_LVL_9_1.yaml new file mode 100644 index 00000000000000..36da12403f5e9d --- /dev/null +++ b/src/app/tests/suites/certification/Test_TC_LVL_9_1.yaml @@ -0,0 +1,264 @@ +# Copyright (c) 2024 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. + +name: 4.2.4. [TC-LVL-9.1] Scenes Management Cluster Interaction (DUT as Server) + +PICS: + - LVL.S + - S.S + +config: + nodeId: 0x12344321 + cluster: "Scenes Management" + endpoint: 1 + G1: + type: group_id + defaultValue: 0x0001 + +tests: + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: + "Step 0a :TH sends KeySetWrite command in the GroupKeyManagement + cluster to DUT using a key that is pre-installed on the TH. + GroupKeySet fields are as follows:" + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a1, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1110000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1110001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1110002, + } + + - label: + "Step 0b: TH binds GroupIds 0x0001 and 0x0002 with GroupKeySetID + 0x01a1 in the GroupKeyMap attribute list on GroupKeyManagement cluster + by writing the GroupKeyMap attribute with two entries as follows:" + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: [{ FabricIndex: 1, GroupId: G1, GroupKeySetID: 0x01a1 }] + + - label: "Step 0c: TH sends a RemoveAllGroups command to DUT." + cluster: "Groups" + endpoint: endpoint + command: "RemoveAllGroups" + + - label: + "Step 1a: TH sends a AddGroup command to DUT with the GroupID field + set to G1." + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: + "Step 1b: TH sends a RemoveAllScenes command to DUT with the GroupID + field set to G1." + command: "RemoveAllScenes" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - label: + "Step 1c: TH sends a GetSceneMembership command to DUT with the + GroupID field set to G1." + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneList" + value: [] + + - label: + "Step 2a: TH sends a MoveToLevel command to DUT, with Level =0 and + TransitionTime =0 (immediate)" + cluster: "Level Control" + command: "MoveToLevel" + arguments: + values: + - name: "Level" + value: 0 + - name: "TransitionTime" + value: 0 + - name: "OptionsMask" + value: 1 + - name: "OptionsOverride" + value: 1 + + - label: "Step 2b: TH reads the MinLevel attribute from the DUT" + cluster: "Level Control" + command: "readAttribute" + attribute: "MinLevel" + response: + saveAs: MinLevelValue + constraints: + type: int8u + + - label: "Step 2c: TH reads the CurrentLevel attribute from DUT" + cluster: "Level Control" + command: "readAttribute" + attribute: "CurrentLevel" + response: + value: MinLevelValue + + - label: + "Step 3: TH sends a StoreScene command to DUT with the GroupID field + set to G1 and the SceneID field set to 0x01." + command: "StoreScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + + - label: "Step 4: TH sends a AddScene command to DUT with the GroupID field + set to G1, the SceneID field set to 0x02, the TransitionTime field set + to 0 and the ExtensionFieldSets set to: '[{ ClusterID: 0x0008, + AttributeValueList: [{ AttributeID: 0x0000, ValueUnsigned8: 0x64 }]}]' + " + command: "AddScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + - name: "TransitionTime" + value: 0 + - name: "SceneName" + value: "Scene1" + - name: "ExtensionFieldSets" + value: + [ + { + ClusterID: 0x0008, + AttributeValueList: + [{ AttributeID: 0x0000, ValueUnsigned8: 0x64 }], + }, + ] + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + + - label: + "Step 5a: TH sends a RecallScene command to DUT with the GroupID field + set to G1 and the SceneID field set to 0x02." + command: "RecallScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + + - label: "Step 5b: TH reads the CurrentLevel attribute from DUT" + cluster: "Level Control" + command: "readAttribute" + attribute: "CurrentLevel" + response: + value: 0x64 + + - label: + "Step 6a: TH sends a RecallScene command to DUT with the GroupID field + set to G1 and the SceneID field set to 0x01." + command: "RecallScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + + - label: "Step 6c: TH reads the CurrentLevel attribute from DUT" + cluster: "Level Control" + command: "readAttribute" + attribute: "CurrentLevel" + response: + value: MinLevelValue + + - label: + "Cleanup: TH sends a RemoveAllScenes command to DUT with the GroupID + field set to G1." + command: "RemoveAllScenes" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + + - label: "Cleanup: TH sends a RemoveAllGroups command to DUT." + cluster: "Groups" + endpoint: endpoint + command: "RemoveAllGroups" diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json index 44cfcd1648a70d..a96ef4aebc8fff 100644 --- a/src/app/tests/suites/ciTests.json +++ b/src/app/tests/suites/ciTests.json @@ -83,7 +83,8 @@ "Test_TC_LVL_4_1", "Test_TC_LVL_5_1", "Test_TC_LVL_6_1", - "Test_TC_LVL_7_1" + "Test_TC_LVL_7_1", + "Test_TC_LVL_9_1" ], "LocalizationConfiguration": [], "TimeFormatLocalization": ["Test_TC_LTIME_1_2", "Test_TC_LTIME_3_1"], From 942112753d5c3e5fa83bb6ee97c4da8b3a02624a Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Thu, 25 Jul 2024 22:22:24 -0400 Subject: [PATCH 15/17] Add XML definition for Ecosystem Information Cluster (#34291) --- .github/workflows/tests.yaml | 1 + docs/zap_clusters.md | 1 + scripts/rules.matterlint | 1 + src/app/zap-templates/zcl/data-model/all.xml | 1 + .../data-model/chip/descriptor-cluster.xml | 1 + .../chip/ecosystem-information-cluster.xml | 60 ++ .../zcl/data-model/chip/global-structs.xml | 1 + .../chip/semantic-tag-namespace-enums.xml | 1 + .../zcl/zcl-with-test-extensions.json | 1 + src/app/zap-templates/zcl/zcl.json | 1 + src/app/zap_cluster_list.json | 2 + .../data_model/controller-clusters.matter | 142 +++ .../chip/devicecontroller/ChipClusters.java | 296 ++++++ .../chip/devicecontroller/ChipStructs.java | 379 +++++++ .../devicecontroller/ClusterIDMapping.java | 106 ++ .../devicecontroller/ClusterInfoMapping.java | 156 +++ .../devicecontroller/ClusterReadMapping.java | 104 ++ .../devicecontroller/ClusterWriteMapping.java | 2 + .../chip/devicecontroller/cluster/files.gni | 4 + ...ystemInformationClusterDeviceTypeStruct.kt | 56 + ...InformationClusterEcosystemDeviceStruct.kt | 142 +++ ...formationClusterEcosystemLocationStruct.kt | 82 ++ ...temInformationClusterHomeLocationStruct.kt | 84 ++ .../clusters/EcosystemInformationCluster.kt | 969 ++++++++++++++++++ .../java/matter/controller/cluster/files.gni | 5 + ...ystemInformationClusterDeviceTypeStruct.kt | 56 + ...InformationClusterEcosystemDeviceStruct.kt | 142 +++ ...formationClusterEcosystemLocationStruct.kt | 82 ++ ...temInformationClusterHomeLocationStruct.kt | 84 ++ .../CHIPAttributeTLVValueDecoder.cpp | 455 ++++++++ .../CHIPEventTLVValueDecoder.cpp | 10 + .../python/chip/clusters/CHIPClusters.py | 64 ++ .../python/chip/clusters/Objects.py | 349 +++++++ .../MTRAttributeSpecifiedCheck.mm | 39 + .../MTRAttributeTLVValueDecoder.mm | 165 +++ .../CHIP/zap-generated/MTRBaseClusters.h | 177 ++++ .../CHIP/zap-generated/MTRBaseClusters.mm | 328 ++++++ .../CHIP/zap-generated/MTRClusterConstants.h | 12 + .../CHIP/zap-generated/MTRClusterNames.mm | 49 + .../CHIP/zap-generated/MTRClusters.h | 42 + .../CHIP/zap-generated/MTRClusters.mm | 49 + .../zap-generated/MTRCommandTimedCheck.mm | 12 + .../zap-generated/MTREventTLVValueDecoder.mm | 15 + .../CHIP/zap-generated/MTRStructsObjc.h | 33 + .../CHIP/zap-generated/MTRStructsObjc.mm | 147 +++ .../zap-generated/attributes/Accessors.cpp | 189 ++++ .../zap-generated/attributes/Accessors.h | 29 + .../app-common/zap-generated/callback.h | 43 + .../zap-generated/cluster-enums-check.h | 210 ++-- .../app-common/zap-generated/cluster-enums.h | 215 ++-- .../zap-generated/cluster-objects.cpp | 398 +++++-- .../zap-generated/cluster-objects.h | 300 +++++- .../app-common/zap-generated/ids/Attributes.h | 42 + .../app-common/zap-generated/ids/Clusters.h | 3 + .../zap-generated/cluster/Commands.h | 86 ++ .../cluster/ComplexArgumentParser.cpp | 270 +++-- .../cluster/ComplexArgumentParser.h | 32 +- .../cluster/logging/DataModelLogger.cpp | 287 ++++-- .../cluster/logging/DataModelLogger.h | 19 +- .../zap-generated/cluster/Commands.h | 849 +++++++++++++++ 60 files changed, 7391 insertions(+), 489 deletions(-) create mode 100644 src/app/zap-templates/zcl/data-model/chip/ecosystem-information-cluster.xml create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/clusters/EcosystemInformationCluster.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 182a3bb3a9fadd..554ee752ff2a08 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -127,6 +127,7 @@ jobs: src/app/zap-templates/zcl/data-model/chip/microwave-oven-mode-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/microwave-oven-control-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/door-lock-cluster.xml \ + src/app/zap-templates/zcl/data-model/chip/ecosystem-information-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/energy-evse-mode-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/ethernet-network-diagnostics-cluster.xml \ diff --git a/docs/zap_clusters.md b/docs/zap_clusters.md index ac9c8f04e7f86f..93e37131626379 100644 --- a/docs/zap_clusters.md +++ b/docs/zap_clusters.md @@ -132,6 +132,7 @@ Generally regenerate using one of: | 1294 | 0x50E | AccountLogin | | 1295 | 0x50F | ContentControl | | 1296 | 0x510 | ContentAppObserver | +| 1872 | 0x750 | EcosystemInformation | | 1873 | 0x751 | CommissionerControl | | 2820 | 0xB04 | ElectricalMeasurement | | 4294048773 | 0xFFF1FC05 | UnitTesting | diff --git a/scripts/rules.matterlint b/scripts/rules.matterlint index f44681febd112d..43b9b5887582b4 100644 --- a/scripts/rules.matterlint +++ b/scripts/rules.matterlint @@ -34,6 +34,7 @@ load "../src/app/zap-templates/zcl/data-model/chip/measurement-and-sensing.xml"; load "../src/app/zap-templates/zcl/data-model/chip/microwave-oven-mode-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/microwave-oven-control-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/door-lock-cluster.xml"; +load "../src/app/zap-templates/zcl/data-model/chip/ecosystem-information-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/energy-evse-mode-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/ethernet-network-diagnostics-cluster.xml"; diff --git a/src/app/zap-templates/zcl/data-model/all.xml b/src/app/zap-templates/zcl/data-model/all.xml index 6003a7cf4a3f1a..2a2f73ccfc1709 100644 --- a/src/app/zap-templates/zcl/data-model/all.xml +++ b/src/app/zap-templates/zcl/data-model/all.xml @@ -34,6 +34,7 @@ + diff --git a/src/app/zap-templates/zcl/data-model/chip/descriptor-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/descriptor-cluster.xml index 639b965cfc9bf9..d63dbeb05ca11a 100644 --- a/src/app/zap-templates/zcl/data-model/chip/descriptor-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/descriptor-cluster.xml @@ -19,6 +19,7 @@ limitations under the License. + diff --git a/src/app/zap-templates/zcl/data-model/chip/ecosystem-information-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/ecosystem-information-cluster.xml new file mode 100644 index 00000000000000..9a34cd3d02b20e --- /dev/null +++ b/src/app/zap-templates/zcl/data-model/chip/ecosystem-information-cluster.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + General + Ecosystem Information + 0x0750 + ECOSYSTEM_INFORMATION_CLUSTER + Provides extended device information for all the logical devices represented by a Bridged Node. + true + true + + + + RemovedOn + + + + DeviceDirectory + + + + LocationDirectory + + + + diff --git a/src/app/zap-templates/zcl/data-model/chip/global-structs.xml b/src/app/zap-templates/zcl/data-model/chip/global-structs.xml index c68c4aa1d000d7..777630ec32b06d 100644 --- a/src/app/zap-templates/zcl/data-model/chip/global-structs.xml +++ b/src/app/zap-templates/zcl/data-model/chip/global-structs.xml @@ -25,6 +25,7 @@ TODO: Make these structures global rather than defining them for each cluster. + diff --git a/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml b/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml index a1572523bcb0b3..8e6d9237e29d90 100644 --- a/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml +++ b/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml @@ -44,6 +44,7 @@ TODO: Make these namespace enums global rather than defining them for each clust + diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 513144d3d32ad9..b06fc9131f3eee 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -48,6 +48,7 @@ "microwave-oven-mode-cluster.xml", "microwave-oven-control-cluster.xml", "door-lock-cluster.xml", + "ecosystem-information-cluster.xml", "energy-preference-cluster.xml", "electrical-energy-measurement-cluster.xml", "electrical-measurement-cluster.xml", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index b497281e585578..921b2022f40f8a 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -46,6 +46,7 @@ "microwave-oven-mode-cluster.xml", "door-lock-cluster.xml", "drlc-cluster.xml", + "ecosystem-information-cluster.xml", "electrical-energy-measurement-cluster.xml", "electrical-measurement-cluster.xml", "electrical-power-measurement-cluster.xml", diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index c17a59678697a8..285bd6e6398b73 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -37,6 +37,7 @@ "DISHWASHER_MODE_CLUSTER": [], "MICROWAVE_OVEN_MODE_CLUSTER": [], "DOOR_LOCK_CLUSTER": [], + "ECOSYSTEM_INFORMATION_CLUSTER": [], "ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER": [], "ELECTRICAL_MEASUREMENT_CLUSTER": [], "ELECTRICAL_POWER_MEASUREMENT_CLUSTER": [], @@ -185,6 +186,7 @@ "DISHWASHER_MODE_CLUSTER": ["mode-base-server"], "MICROWAVE_OVEN_MODE_CLUSTER": ["mode-base-server"], "DOOR_LOCK_CLUSTER": ["door-lock-server"], + "ECOSYSTEM_INFORMATION_CLUSTER": [], "ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER": [ "electrical-energy-measurement-server" ], diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 39a4d56bfd69b8..a1ed710504df8a 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -9245,6 +9245,148 @@ provisional cluster ContentAppObserver = 1296 { command ContentAppMessage(ContentAppMessageRequest): ContentAppMessageResponse = 0; } +/** Provides extended device information for all the logical devices represented by a Bridged Node. */ +provisional cluster EcosystemInformation = 1872 { + revision 1; + + enum AreaTypeTag : enum8 { + kAisle = 0; + kAttic = 1; + kBackDoor = 2; + kBackYard = 3; + kBalcony = 4; + kBallroom = 5; + kBathroom = 6; + kBedroom = 7; + kBorder = 8; + kBoxroom = 9; + kBreakfastRoom = 10; + kCarport = 11; + kCellar = 12; + kCloakroom = 13; + kCloset = 14; + kConservatory = 15; + kCorridor = 16; + kCraftRoom = 17; + kCupboard = 18; + kDeck = 19; + kDen = 20; + kDining = 21; + kDrawingRoom = 22; + kDressingRoom = 23; + kDriveway = 24; + kElevator = 25; + kEnsuite = 26; + kEntrance = 27; + kEntryway = 28; + kFamilyRoom = 29; + kFoyer = 30; + kFrontDoor = 31; + kFrontYard = 32; + kGameRoom = 33; + kGarage = 34; + kGarageDoor = 35; + kGarden = 36; + kGardenDoor = 37; + kGuestBathroom = 38; + kGuestBedroom = 39; + kGuestRestroom = 40; + kGuestRoom = 41; + kGym = 42; + kHallway = 43; + kHearthRoom = 44; + kKidsRoom = 45; + kKidsBedroom = 46; + kKitchen = 47; + kLarder = 48; + kLaundryRoom = 49; + kLawn = 50; + kLibrary = 51; + kLivingRoom = 52; + kLounge = 53; + kMediaTVRoom = 54; + kMudRoom = 55; + kMusicRoom = 56; + kNursery = 57; + kOffice = 58; + kOutdoorKitchen = 59; + kOutside = 60; + kPantry = 61; + kParkingLot = 62; + kParlor = 63; + kPatio = 64; + kPlayRoom = 65; + kPoolRoom = 66; + kPorch = 67; + kPrimaryBathroom = 68; + kPrimaryBedroom = 69; + kRamp = 70; + kReceptionRoom = 71; + kRecreationRoom = 72; + kRestroom = 73; + kRoof = 74; + kSauna = 75; + kScullery = 76; + kSewingRoom = 77; + kShed = 78; + kSideDoor = 79; + kSideYard = 80; + kSittingRoom = 81; + kSnug = 82; + kSpa = 83; + kStaircase = 84; + kSteamRoom = 85; + kStorageRoom = 86; + kStudio = 87; + kStudy = 88; + kSunRoom = 89; + kSwimmingPool = 90; + kTerrace = 91; + kUtilityRoom = 92; + kWard = 93; + kWorkshop = 94; + } + + struct HomeLocationStruct { + char_string<128> locationName = 0; + nullable int16s floorNumber = 1; + nullable AreaTypeTag areaType = 2; + } + + fabric_scoped struct EcosystemLocationStruct { + fabric_sensitive char_string<64> uniqueLocationID = 0; + fabric_sensitive HomeLocationStruct locationDescriptor = 1; + fabric_sensitive epoch_us locationDescriptorLastEdit = 2; + fabric_idx fabricIndex = 254; + } + + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + fabric_scoped struct EcosystemDeviceStruct { + optional fabric_sensitive char_string<64> deviceName = 0; + optional fabric_sensitive epoch_us deviceNameLastEdit = 1; + fabric_sensitive endpoint_no bridgedEndpoint = 2; + fabric_sensitive endpoint_no originalEndpoint = 3; + fabric_sensitive DeviceTypeStruct deviceTypes[] = 4; + fabric_sensitive char_string uniqueLocationIDs[] = 5; + fabric_sensitive epoch_us uniqueLocationIDsLastEdit = 6; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: manage) optional nullable epoch_us removedOn = 0; + readonly attribute access(read: manage) EcosystemDeviceStruct deviceDirectory[] = 1; + readonly attribute access(read: manage) EcosystemLocationStruct locationDirectory[] = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + /** Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. */ provisional cluster CommissionerControl = 1873 { revision 1; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index bbdc1dea185456..e11a47a23a8c7c 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -60522,6 +60522,302 @@ public void onSuccess(byte[] tlv) { } } + public static class EcosystemInformationCluster extends BaseChipCluster { + public static final long CLUSTER_ID = 1872L; + + private static final long REMOVED_ON_ATTRIBUTE_ID = 0L; + private static final long DEVICE_DIRECTORY_ATTRIBUTE_ID = 1L; + private static final long LOCATION_DIRECTORY_ATTRIBUTE_ID = 2L; + private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L; + private static final long ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID = 65529L; + private static final long EVENT_LIST_ATTRIBUTE_ID = 65530L; + private static final long ATTRIBUTE_LIST_ATTRIBUTE_ID = 65531L; + private static final long FEATURE_MAP_ATTRIBUTE_ID = 65532L; + private static final long CLUSTER_REVISION_ATTRIBUTE_ID = 65533L; + + public EcosystemInformationCluster(long devicePtr, int endpointId) { + super(devicePtr, endpointId, CLUSTER_ID); + } + + @Override + @Deprecated + public long initWithDevice(long devicePtr, int endpointId) { + return 0L; + } + + public interface RemovedOnAttributeCallback extends BaseAttributeCallback { + void onSuccess(@Nullable Long value); + } + + public interface DeviceDirectoryAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface LocationDirectoryAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface GeneratedCommandListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface AcceptedCommandListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface EventListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface AttributeListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public void readRemovedOnAttribute( + RemovedOnAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, REMOVED_ON_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + @Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, REMOVED_ON_ATTRIBUTE_ID, true); + } + + public void subscribeRemovedOnAttribute( + RemovedOnAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, REMOVED_ON_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + @Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, REMOVED_ON_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readDeviceDirectoryAttribute( + DeviceDirectoryAttributeCallback callback) { + readDeviceDirectoryAttributeWithFabricFilter(callback, true); + } + + public void readDeviceDirectoryAttributeWithFabricFilter( + DeviceDirectoryAttributeCallback callback, boolean isFabricFiltered) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, DEVICE_DIRECTORY_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, DEVICE_DIRECTORY_ATTRIBUTE_ID, isFabricFiltered); + } + + public void subscribeDeviceDirectoryAttribute( + DeviceDirectoryAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, DEVICE_DIRECTORY_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, DEVICE_DIRECTORY_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readLocationDirectoryAttribute( + LocationDirectoryAttributeCallback callback) { + readLocationDirectoryAttributeWithFabricFilter(callback, true); + } + + public void readLocationDirectoryAttributeWithFabricFilter( + LocationDirectoryAttributeCallback callback, boolean isFabricFiltered) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, LOCATION_DIRECTORY_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, LOCATION_DIRECTORY_ATTRIBUTE_ID, isFabricFiltered); + } + + public void subscribeLocationDirectoryAttribute( + LocationDirectoryAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, LOCATION_DIRECTORY_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, LOCATION_DIRECTORY_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readGeneratedCommandListAttribute( + GeneratedCommandListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, GENERATED_COMMAND_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeGeneratedCommandListAttribute( + GeneratedCommandListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, GENERATED_COMMAND_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readAcceptedCommandListAttribute( + AcceptedCommandListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeAcceptedCommandListAttribute( + AcceptedCommandListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readEventListAttribute( + EventListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, EVENT_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, EVENT_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeEventListAttribute( + EventListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, EVENT_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, EVENT_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readAttributeListAttribute( + AttributeListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ATTRIBUTE_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ATTRIBUTE_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeAttributeListAttribute( + AttributeListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ATTRIBUTE_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ATTRIBUTE_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readFeatureMapAttribute( + LongAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, FEATURE_MAP_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, FEATURE_MAP_ATTRIBUTE_ID, true); + } + + public void subscribeFeatureMapAttribute( + LongAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, FEATURE_MAP_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, FEATURE_MAP_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readClusterRevisionAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CLUSTER_REVISION_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, CLUSTER_REVISION_ATTRIBUTE_ID, true); + } + + public void subscribeClusterRevisionAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CLUSTER_REVISION_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, CLUSTER_REVISION_ATTRIBUTE_ID, minInterval, maxInterval); + } + } + public static class CommissionerControlCluster extends BaseChipCluster { public static final long CLUSTER_ID = 1873L; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java index c62c3062fa3bc4..075e3dbd45ed0e 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java @@ -12283,6 +12283,385 @@ public String toString() { return output.toString(); } } +public static class EcosystemInformationClusterHomeLocationStruct { + public String locationName; + public @Nullable Integer floorNumber; + public @Nullable Integer areaType; + private static final long LOCATION_NAME_ID = 0L; + private static final long FLOOR_NUMBER_ID = 1L; + private static final long AREA_TYPE_ID = 2L; + + public EcosystemInformationClusterHomeLocationStruct( + String locationName, + @Nullable Integer floorNumber, + @Nullable Integer areaType + ) { + this.locationName = locationName; + this.floorNumber = floorNumber; + this.areaType = areaType; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(LOCATION_NAME_ID, new StringType(locationName))); + values.add(new StructElement(FLOOR_NUMBER_ID, floorNumber != null ? new IntType(floorNumber) : new NullType())); + values.add(new StructElement(AREA_TYPE_ID, areaType != null ? new UIntType(areaType) : new NullType())); + + return new StructType(values); + } + + public static EcosystemInformationClusterHomeLocationStruct decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + String locationName = null; + @Nullable Integer floorNumber = null; + @Nullable Integer areaType = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == LOCATION_NAME_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.String) { + StringType castingValue = element.value(StringType.class); + locationName = castingValue.value(String.class); + } + } else if (element.contextTagNum() == FLOOR_NUMBER_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.Int) { + IntType castingValue = element.value(IntType.class); + floorNumber = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == AREA_TYPE_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + areaType = castingValue.value(Integer.class); + } + } + } + return new EcosystemInformationClusterHomeLocationStruct( + locationName, + floorNumber, + areaType + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("EcosystemInformationClusterHomeLocationStruct {\n"); + output.append("\tlocationName: "); + output.append(locationName); + output.append("\n"); + output.append("\tfloorNumber: "); + output.append(floorNumber); + output.append("\n"); + output.append("\tareaType: "); + output.append(areaType); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} +public static class EcosystemInformationClusterEcosystemLocationStruct { + public String uniqueLocationID; + public ChipStructs.EcosystemInformationClusterHomeLocationStruct locationDescriptor; + public Long locationDescriptorLastEdit; + public Integer fabricIndex; + private static final long UNIQUE_LOCATION_I_D_ID = 0L; + private static final long LOCATION_DESCRIPTOR_ID = 1L; + private static final long LOCATION_DESCRIPTOR_LAST_EDIT_ID = 2L; + private static final long FABRIC_INDEX_ID = 254L; + + public EcosystemInformationClusterEcosystemLocationStruct( + String uniqueLocationID, + ChipStructs.EcosystemInformationClusterHomeLocationStruct locationDescriptor, + Long locationDescriptorLastEdit, + Integer fabricIndex + ) { + this.uniqueLocationID = uniqueLocationID; + this.locationDescriptor = locationDescriptor; + this.locationDescriptorLastEdit = locationDescriptorLastEdit; + this.fabricIndex = fabricIndex; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(UNIQUE_LOCATION_I_D_ID, new StringType(uniqueLocationID))); + values.add(new StructElement(LOCATION_DESCRIPTOR_ID, locationDescriptor.encodeTlv())); + values.add(new StructElement(LOCATION_DESCRIPTOR_LAST_EDIT_ID, new UIntType(locationDescriptorLastEdit))); + values.add(new StructElement(FABRIC_INDEX_ID, new UIntType(fabricIndex))); + + return new StructType(values); + } + + public static EcosystemInformationClusterEcosystemLocationStruct decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + String uniqueLocationID = null; + ChipStructs.EcosystemInformationClusterHomeLocationStruct locationDescriptor = null; + Long locationDescriptorLastEdit = null; + Integer fabricIndex = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == UNIQUE_LOCATION_I_D_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.String) { + StringType castingValue = element.value(StringType.class); + uniqueLocationID = castingValue.value(String.class); + } + } else if (element.contextTagNum() == LOCATION_DESCRIPTOR_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.Struct) { + StructType castingValue = element.value(StructType.class); + locationDescriptor = ChipStructs.EcosystemInformationClusterHomeLocationStruct.decodeTlv(castingValue); + } + } else if (element.contextTagNum() == LOCATION_DESCRIPTOR_LAST_EDIT_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + locationDescriptorLastEdit = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == FABRIC_INDEX_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + fabricIndex = castingValue.value(Integer.class); + } + } + } + return new EcosystemInformationClusterEcosystemLocationStruct( + uniqueLocationID, + locationDescriptor, + locationDescriptorLastEdit, + fabricIndex + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("EcosystemInformationClusterEcosystemLocationStruct {\n"); + output.append("\tuniqueLocationID: "); + output.append(uniqueLocationID); + output.append("\n"); + output.append("\tlocationDescriptor: "); + output.append(locationDescriptor); + output.append("\n"); + output.append("\tlocationDescriptorLastEdit: "); + output.append(locationDescriptorLastEdit); + output.append("\n"); + output.append("\tfabricIndex: "); + output.append(fabricIndex); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} +public static class EcosystemInformationClusterDeviceTypeStruct { + public Long deviceType; + public Integer revision; + private static final long DEVICE_TYPE_ID = 0L; + private static final long REVISION_ID = 1L; + + public EcosystemInformationClusterDeviceTypeStruct( + Long deviceType, + Integer revision + ) { + this.deviceType = deviceType; + this.revision = revision; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(DEVICE_TYPE_ID, new UIntType(deviceType))); + values.add(new StructElement(REVISION_ID, new UIntType(revision))); + + return new StructType(values); + } + + public static EcosystemInformationClusterDeviceTypeStruct decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + Long deviceType = null; + Integer revision = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == DEVICE_TYPE_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + deviceType = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == REVISION_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + revision = castingValue.value(Integer.class); + } + } + } + return new EcosystemInformationClusterDeviceTypeStruct( + deviceType, + revision + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("EcosystemInformationClusterDeviceTypeStruct {\n"); + output.append("\tdeviceType: "); + output.append(deviceType); + output.append("\n"); + output.append("\trevision: "); + output.append(revision); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} +public static class EcosystemInformationClusterEcosystemDeviceStruct { + public Optional deviceName; + public Optional deviceNameLastEdit; + public Integer bridgedEndpoint; + public Integer originalEndpoint; + public ArrayList deviceTypes; + public ArrayList uniqueLocationIDs; + public Long uniqueLocationIDsLastEdit; + public Integer fabricIndex; + private static final long DEVICE_NAME_ID = 0L; + private static final long DEVICE_NAME_LAST_EDIT_ID = 1L; + private static final long BRIDGED_ENDPOINT_ID = 2L; + private static final long ORIGINAL_ENDPOINT_ID = 3L; + private static final long DEVICE_TYPES_ID = 4L; + private static final long UNIQUE_LOCATION_I_DS_ID = 5L; + private static final long UNIQUE_LOCATION_I_DS_LAST_EDIT_ID = 6L; + private static final long FABRIC_INDEX_ID = 254L; + + public EcosystemInformationClusterEcosystemDeviceStruct( + Optional deviceName, + Optional deviceNameLastEdit, + Integer bridgedEndpoint, + Integer originalEndpoint, + ArrayList deviceTypes, + ArrayList uniqueLocationIDs, + Long uniqueLocationIDsLastEdit, + Integer fabricIndex + ) { + this.deviceName = deviceName; + this.deviceNameLastEdit = deviceNameLastEdit; + this.bridgedEndpoint = bridgedEndpoint; + this.originalEndpoint = originalEndpoint; + this.deviceTypes = deviceTypes; + this.uniqueLocationIDs = uniqueLocationIDs; + this.uniqueLocationIDsLastEdit = uniqueLocationIDsLastEdit; + this.fabricIndex = fabricIndex; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(DEVICE_NAME_ID, deviceName.map((nonOptionaldeviceName) -> new StringType(nonOptionaldeviceName)).orElse(new EmptyType()))); + values.add(new StructElement(DEVICE_NAME_LAST_EDIT_ID, deviceNameLastEdit.map((nonOptionaldeviceNameLastEdit) -> new UIntType(nonOptionaldeviceNameLastEdit)).orElse(new EmptyType()))); + values.add(new StructElement(BRIDGED_ENDPOINT_ID, new UIntType(bridgedEndpoint))); + values.add(new StructElement(ORIGINAL_ENDPOINT_ID, new UIntType(originalEndpoint))); + values.add(new StructElement(DEVICE_TYPES_ID, ArrayType.generateArrayType(deviceTypes, (elementdeviceTypes) -> elementdeviceTypes.encodeTlv()))); + values.add(new StructElement(UNIQUE_LOCATION_I_DS_ID, ArrayType.generateArrayType(uniqueLocationIDs, (elementuniqueLocationIDs) -> new StringType(elementuniqueLocationIDs)))); + values.add(new StructElement(UNIQUE_LOCATION_I_DS_LAST_EDIT_ID, new UIntType(uniqueLocationIDsLastEdit))); + values.add(new StructElement(FABRIC_INDEX_ID, new UIntType(fabricIndex))); + + return new StructType(values); + } + + public static EcosystemInformationClusterEcosystemDeviceStruct decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + Optional deviceName = Optional.empty(); + Optional deviceNameLastEdit = Optional.empty(); + Integer bridgedEndpoint = null; + Integer originalEndpoint = null; + ArrayList deviceTypes = null; + ArrayList uniqueLocationIDs = null; + Long uniqueLocationIDsLastEdit = null; + Integer fabricIndex = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == DEVICE_NAME_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.String) { + StringType castingValue = element.value(StringType.class); + deviceName = Optional.of(castingValue.value(String.class)); + } + } else if (element.contextTagNum() == DEVICE_NAME_LAST_EDIT_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + deviceNameLastEdit = Optional.of(castingValue.value(Long.class)); + } + } else if (element.contextTagNum() == BRIDGED_ENDPOINT_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + bridgedEndpoint = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == ORIGINAL_ENDPOINT_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + originalEndpoint = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == DEVICE_TYPES_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.Array) { + ArrayType castingValue = element.value(ArrayType.class); + deviceTypes = castingValue.map((elementcastingValue) -> ChipStructs.EcosystemInformationClusterDeviceTypeStruct.decodeTlv(elementcastingValue)); + } + } else if (element.contextTagNum() == UNIQUE_LOCATION_I_DS_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.Array) { + ArrayType castingValue = element.value(ArrayType.class); + uniqueLocationIDs = castingValue.map((elementcastingValue) -> elementcastingValue.value(String.class)); + } + } else if (element.contextTagNum() == UNIQUE_LOCATION_I_DS_LAST_EDIT_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + uniqueLocationIDsLastEdit = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == FABRIC_INDEX_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + fabricIndex = castingValue.value(Integer.class); + } + } + } + return new EcosystemInformationClusterEcosystemDeviceStruct( + deviceName, + deviceNameLastEdit, + bridgedEndpoint, + originalEndpoint, + deviceTypes, + uniqueLocationIDs, + uniqueLocationIDsLastEdit, + fabricIndex + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("EcosystemInformationClusterEcosystemDeviceStruct {\n"); + output.append("\tdeviceName: "); + output.append(deviceName); + output.append("\n"); + output.append("\tdeviceNameLastEdit: "); + output.append(deviceNameLastEdit); + output.append("\n"); + output.append("\tbridgedEndpoint: "); + output.append(bridgedEndpoint); + output.append("\n"); + output.append("\toriginalEndpoint: "); + output.append(originalEndpoint); + output.append("\n"); + output.append("\tdeviceTypes: "); + output.append(deviceTypes); + output.append("\n"); + output.append("\tuniqueLocationIDs: "); + output.append(uniqueLocationIDs); + output.append("\n"); + output.append("\tuniqueLocationIDsLastEdit: "); + output.append(uniqueLocationIDsLastEdit); + output.append("\n"); + output.append("\tfabricIndex: "); + output.append(fabricIndex); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} public static class UnitTestingClusterSimpleStruct { public Integer a; public Boolean b; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index 72972b2554c102..ab20bdcaa301e9 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -388,6 +388,9 @@ public static BaseCluster getCluster(long clusterId) { if (clusterId == ContentAppObserver.ID) { return new ContentAppObserver(); } + if (clusterId == EcosystemInformation.ID) { + return new EcosystemInformation(); + } if (clusterId == CommissionerControl.ID) { return new CommissionerControl(); } @@ -17166,6 +17169,109 @@ public long getCommandID(String name) throws IllegalArgumentException { return Command.valueOf(name).getID(); } } + public static class EcosystemInformation implements BaseCluster { + public static final long ID = 1872L; + public long getID() { + return ID; + } + + public enum Attribute { + RemovedOn(0L), + DeviceDirectory(1L), + LocationDirectory(2L), + GeneratedCommandList(65528L), + AcceptedCommandList(65529L), + EventList(65530L), + AttributeList(65531L), + FeatureMap(65532L), + ClusterRevision(65533L),; + private final long id; + Attribute(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Attribute value(long id) throws NoSuchFieldError { + for (Attribute attribute : Attribute.values()) { + if (attribute.getID() == id) { + return attribute; + } + } + throw new NoSuchFieldError(); + } + } + + public enum Event {; + private final long id; + Event(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Event value(long id) throws NoSuchFieldError { + for (Event event : Event.values()) { + if (event.getID() == id) { + return event; + } + } + throw new NoSuchFieldError(); + } + } + + public enum Command {; + private final long id; + Command(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Command value(long id) throws NoSuchFieldError { + for (Command command : Command.values()) { + if (command.getID() == id) { + return command; + } + } + throw new NoSuchFieldError(); + } + }@Override + public String getAttributeName(long id) throws NoSuchFieldError { + return Attribute.value(id).toString(); + } + + @Override + public String getEventName(long id) throws NoSuchFieldError { + return Event.value(id).toString(); + } + + @Override + public String getCommandName(long id) throws NoSuchFieldError { + return Command.value(id).toString(); + } + + @Override + public long getAttributeID(String name) throws IllegalArgumentException { + return Attribute.valueOf(name).getID(); + } + + @Override + public long getEventID(String name) throws IllegalArgumentException { + return Event.valueOf(name).getID(); + } + + @Override + public long getCommandID(String name) throws IllegalArgumentException { + return Command.valueOf(name).getID(); + } + } public static class CommissionerControl implements BaseCluster { public static final long ID = 1873L; public long getID() { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 98a276983b8670..ca3d74f1ac3797 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -20089,6 +20089,153 @@ public void onError(Exception ex) { } } + public static class DelegatedEcosystemInformationClusterRemovedOnAttributeCallback implements ChipClusters.EcosystemInformationCluster.RemovedOnAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(@Nullable Long value) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("value", "Long"); + responseValues.put(commandResponseInfo, value); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedEcosystemInformationClusterDeviceDirectoryAttributeCallback implements ChipClusters.EcosystemInformationCluster.DeviceDirectoryAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedEcosystemInformationClusterLocationDirectoryAttributeCallback implements ChipClusters.EcosystemInformationCluster.LocationDirectoryAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedEcosystemInformationClusterGeneratedCommandListAttributeCallback implements ChipClusters.EcosystemInformationCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedEcosystemInformationClusterAcceptedCommandListAttributeCallback implements ChipClusters.EcosystemInformationCluster.AcceptedCommandListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedEcosystemInformationClusterEventListAttributeCallback implements ChipClusters.EcosystemInformationCluster.EventListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedEcosystemInformationClusterAttributeListAttributeCallback implements ChipClusters.EcosystemInformationCluster.AttributeListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + public static class DelegatedCommissionerControlClusterReverseOpenCommissioningWindowCallback implements ChipClusters.CommissionerControlCluster.ReverseOpenCommissioningWindowCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @@ -22308,6 +22455,10 @@ public Map initializeClusterMap() { (ptr, endpointId) -> new ChipClusters.ContentAppObserverCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("contentAppObserver", contentAppObserverClusterInfo); + ClusterInfo ecosystemInformationClusterInfo = new ClusterInfo( + (ptr, endpointId) -> new ChipClusters.EcosystemInformationCluster(ptr, endpointId), new HashMap<>()); + clusterMap.put("ecosystemInformation", ecosystemInformationClusterInfo); + ClusterInfo commissionerControlClusterInfo = new ClusterInfo( (ptr, endpointId) -> new ChipClusters.CommissionerControlCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("commissionerControl", commissionerControlClusterInfo); @@ -22452,6 +22603,7 @@ public void combineCommand(Map destination, Map> getCommandMap() { commandMap.put("contentAppObserver", contentAppObserverClusterInteractionInfoMap); + Map ecosystemInformationClusterInteractionInfoMap = new LinkedHashMap<>(); + + commandMap.put("ecosystemInformation", ecosystemInformationClusterInteractionInfoMap); + Map commissionerControlClusterInteractionInfoMap = new LinkedHashMap<>(); Map commissionerControlrequestCommissioningApprovalCommandParams = new LinkedHashMap(); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index 04c849e6c0eb9c..45d0e3037631fb 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -18600,6 +18600,109 @@ private static Map readContentAppObserverInteractionInf return result; } + private static Map readEcosystemInformationInteractionInfo() { + Map result = new LinkedHashMap<>();Map readEcosystemInformationRemovedOnCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationRemovedOnAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readRemovedOnAttribute( + (ChipClusters.EcosystemInformationCluster.RemovedOnAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterRemovedOnAttributeCallback(), + readEcosystemInformationRemovedOnCommandParams + ); + result.put("readRemovedOnAttribute", readEcosystemInformationRemovedOnAttributeInteractionInfo); + Map readEcosystemInformationDeviceDirectoryCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationDeviceDirectoryAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readDeviceDirectoryAttribute( + (ChipClusters.EcosystemInformationCluster.DeviceDirectoryAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterDeviceDirectoryAttributeCallback(), + readEcosystemInformationDeviceDirectoryCommandParams + ); + result.put("readDeviceDirectoryAttribute", readEcosystemInformationDeviceDirectoryAttributeInteractionInfo); + Map readEcosystemInformationLocationDirectoryCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationLocationDirectoryAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readLocationDirectoryAttribute( + (ChipClusters.EcosystemInformationCluster.LocationDirectoryAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterLocationDirectoryAttributeCallback(), + readEcosystemInformationLocationDirectoryCommandParams + ); + result.put("readLocationDirectoryAttribute", readEcosystemInformationLocationDirectoryAttributeInteractionInfo); + Map readEcosystemInformationGeneratedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationGeneratedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readGeneratedCommandListAttribute( + (ChipClusters.EcosystemInformationCluster.GeneratedCommandListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterGeneratedCommandListAttributeCallback(), + readEcosystemInformationGeneratedCommandListCommandParams + ); + result.put("readGeneratedCommandListAttribute", readEcosystemInformationGeneratedCommandListAttributeInteractionInfo); + Map readEcosystemInformationAcceptedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationAcceptedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readAcceptedCommandListAttribute( + (ChipClusters.EcosystemInformationCluster.AcceptedCommandListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterAcceptedCommandListAttributeCallback(), + readEcosystemInformationAcceptedCommandListCommandParams + ); + result.put("readAcceptedCommandListAttribute", readEcosystemInformationAcceptedCommandListAttributeInteractionInfo); + Map readEcosystemInformationEventListCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationEventListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readEventListAttribute( + (ChipClusters.EcosystemInformationCluster.EventListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterEventListAttributeCallback(), + readEcosystemInformationEventListCommandParams + ); + result.put("readEventListAttribute", readEcosystemInformationEventListAttributeInteractionInfo); + Map readEcosystemInformationAttributeListCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationAttributeListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readAttributeListAttribute( + (ChipClusters.EcosystemInformationCluster.AttributeListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedEcosystemInformationClusterAttributeListAttributeCallback(), + readEcosystemInformationAttributeListCommandParams + ); + result.put("readAttributeListAttribute", readEcosystemInformationAttributeListAttributeInteractionInfo); + Map readEcosystemInformationFeatureMapCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationFeatureMapAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readFeatureMapAttribute( + (ChipClusters.LongAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedLongAttributeCallback(), + readEcosystemInformationFeatureMapCommandParams + ); + result.put("readFeatureMapAttribute", readEcosystemInformationFeatureMapAttributeInteractionInfo); + Map readEcosystemInformationClusterRevisionCommandParams = new LinkedHashMap(); + InteractionInfo readEcosystemInformationClusterRevisionAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.EcosystemInformationCluster) cluster).readClusterRevisionAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readEcosystemInformationClusterRevisionCommandParams + ); + result.put("readClusterRevisionAttribute", readEcosystemInformationClusterRevisionAttributeInteractionInfo); + + return result; + } private static Map readCommissionerControlInteractionInfo() { Map result = new LinkedHashMap<>();Map readCommissionerControlSupportedDeviceCategoriesCommandParams = new LinkedHashMap(); InteractionInfo readCommissionerControlSupportedDeviceCategoriesAttributeInteractionInfo = new InteractionInfo( @@ -21395,6 +21498,7 @@ public Map> getReadAttributeMap() { put("accountLogin", readAccountLoginInteractionInfo()); put("contentControl", readContentControlInteractionInfo()); put("contentAppObserver", readContentAppObserverInteractionInfo()); + put("ecosystemInformation", readEcosystemInformationInteractionInfo()); put("commissionerControl", readCommissionerControlInteractionInfo()); put("electricalMeasurement", readElectricalMeasurementInteractionInfo()); put("unitTesting", readUnitTestingInteractionInfo()); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index 28cba2abd728f8..32759bb97af64c 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -3764,6 +3764,8 @@ public Map> getWriteAttributeMap() { writeAttributeMap.put("contentControl", writeContentControlInteractionInfo); Map writeContentAppObserverInteractionInfo = new LinkedHashMap<>(); writeAttributeMap.put("contentAppObserver", writeContentAppObserverInteractionInfo); + Map writeEcosystemInformationInteractionInfo = new LinkedHashMap<>(); + writeAttributeMap.put("ecosystemInformation", writeEcosystemInformationInteractionInfo); Map writeCommissionerControlInteractionInfo = new LinkedHashMap<>(); writeAttributeMap.put("commissionerControl", writeCommissionerControlInteractionInfo); Map writeElectricalMeasurementInteractionInfo = new LinkedHashMap<>(); diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index 90ce4a42ae206f..ea8a94605f8ca8 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -56,6 +56,10 @@ structs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/DishwasherModeClusterModeOptionStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/DishwasherModeClusterModeTagStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/DoorLockClusterCredentialStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ElectricalEnergyMeasurementClusterCumulativeEnergyResetStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ElectricalEnergyMeasurementClusterEnergyMeasurementStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ElectricalEnergyMeasurementClusterMeasurementAccuracyRangeStruct.kt", diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt new file mode 100644 index 00000000000000..a5974dea0c190e --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2023 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. + */ +package chip.devicecontroller.cluster.structs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterDeviceTypeStruct(val deviceType: ULong, val revision: UInt) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterDeviceTypeStruct {\n") + append("\tdeviceType : $deviceType\n") + append("\trevision : $revision\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_DEVICE_TYPE), deviceType) + put(ContextSpecificTag(TAG_REVISION), revision) + endStructure() + } + } + + companion object { + private const val TAG_DEVICE_TYPE = 0 + private const val TAG_REVISION = 1 + + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): EcosystemInformationClusterDeviceTypeStruct { + tlvReader.enterStructure(tlvTag) + val deviceType = tlvReader.getULong(ContextSpecificTag(TAG_DEVICE_TYPE)) + val revision = tlvReader.getUInt(ContextSpecificTag(TAG_REVISION)) + + tlvReader.exitContainer() + + return EcosystemInformationClusterDeviceTypeStruct(deviceType, revision) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt new file mode 100644 index 00000000000000..c603107ebf7449 --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt @@ -0,0 +1,142 @@ +/* + * + * Copyright (c) 2023 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. + */ +package chip.devicecontroller.cluster.structs + +import chip.devicecontroller.cluster.* +import java.util.Optional +import matter.tlv.AnonymousTag +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterEcosystemDeviceStruct( + val deviceName: Optional, + val deviceNameLastEdit: Optional, + val bridgedEndpoint: UInt, + val originalEndpoint: UInt, + val deviceTypes: List, + val uniqueLocationIDs: List, + val uniqueLocationIDsLastEdit: ULong, + val fabricIndex: UInt, +) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterEcosystemDeviceStruct {\n") + append("\tdeviceName : $deviceName\n") + append("\tdeviceNameLastEdit : $deviceNameLastEdit\n") + append("\tbridgedEndpoint : $bridgedEndpoint\n") + append("\toriginalEndpoint : $originalEndpoint\n") + append("\tdeviceTypes : $deviceTypes\n") + append("\tuniqueLocationIDs : $uniqueLocationIDs\n") + append("\tuniqueLocationIDsLastEdit : $uniqueLocationIDsLastEdit\n") + append("\tfabricIndex : $fabricIndex\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + if (deviceName.isPresent) { + val optdeviceName = deviceName.get() + put(ContextSpecificTag(TAG_DEVICE_NAME), optdeviceName) + } + if (deviceNameLastEdit.isPresent) { + val optdeviceNameLastEdit = deviceNameLastEdit.get() + put(ContextSpecificTag(TAG_DEVICE_NAME_LAST_EDIT), optdeviceNameLastEdit) + } + put(ContextSpecificTag(TAG_BRIDGED_ENDPOINT), bridgedEndpoint) + put(ContextSpecificTag(TAG_ORIGINAL_ENDPOINT), originalEndpoint) + startArray(ContextSpecificTag(TAG_DEVICE_TYPES)) + for (item in deviceTypes.iterator()) { + item.toTlv(AnonymousTag, this) + } + endArray() + startArray(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS)) + for (item in uniqueLocationIDs.iterator()) { + put(AnonymousTag, item) + } + endArray() + put(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS_LAST_EDIT), uniqueLocationIDsLastEdit) + put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex) + endStructure() + } + } + + companion object { + private const val TAG_DEVICE_NAME = 0 + private const val TAG_DEVICE_NAME_LAST_EDIT = 1 + private const val TAG_BRIDGED_ENDPOINT = 2 + private const val TAG_ORIGINAL_ENDPOINT = 3 + private const val TAG_DEVICE_TYPES = 4 + private const val TAG_UNIQUE_LOCATION_I_DS = 5 + private const val TAG_UNIQUE_LOCATION_I_DS_LAST_EDIT = 6 + private const val TAG_FABRIC_INDEX = 254 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): EcosystemInformationClusterEcosystemDeviceStruct { + tlvReader.enterStructure(tlvTag) + val deviceName = + if (tlvReader.isNextTag(ContextSpecificTag(TAG_DEVICE_NAME))) { + Optional.of(tlvReader.getString(ContextSpecificTag(TAG_DEVICE_NAME))) + } else { + Optional.empty() + } + val deviceNameLastEdit = + if (tlvReader.isNextTag(ContextSpecificTag(TAG_DEVICE_NAME_LAST_EDIT))) { + Optional.of(tlvReader.getULong(ContextSpecificTag(TAG_DEVICE_NAME_LAST_EDIT))) + } else { + Optional.empty() + } + val bridgedEndpoint = tlvReader.getUInt(ContextSpecificTag(TAG_BRIDGED_ENDPOINT)) + val originalEndpoint = tlvReader.getUInt(ContextSpecificTag(TAG_ORIGINAL_ENDPOINT)) + val deviceTypes = + buildList { + tlvReader.enterArray(ContextSpecificTag(TAG_DEVICE_TYPES)) + while (!tlvReader.isEndOfContainer()) { + add(EcosystemInformationClusterDeviceTypeStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + val uniqueLocationIDs = + buildList { + tlvReader.enterArray(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS)) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + val uniqueLocationIDsLastEdit = + tlvReader.getULong(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS_LAST_EDIT)) + val fabricIndex = tlvReader.getUInt(ContextSpecificTag(TAG_FABRIC_INDEX)) + + tlvReader.exitContainer() + + return EcosystemInformationClusterEcosystemDeviceStruct( + deviceName, + deviceNameLastEdit, + bridgedEndpoint, + originalEndpoint, + deviceTypes, + uniqueLocationIDs, + uniqueLocationIDsLastEdit, + fabricIndex, + ) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt new file mode 100644 index 00000000000000..c9db75b3082344 --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2023 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. + */ +package chip.devicecontroller.cluster.structs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterEcosystemLocationStruct( + val uniqueLocationID: String, + val locationDescriptor: EcosystemInformationClusterHomeLocationStruct, + val locationDescriptorLastEdit: ULong, + val fabricIndex: UInt, +) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterEcosystemLocationStruct {\n") + append("\tuniqueLocationID : $uniqueLocationID\n") + append("\tlocationDescriptor : $locationDescriptor\n") + append("\tlocationDescriptorLastEdit : $locationDescriptorLastEdit\n") + append("\tfabricIndex : $fabricIndex\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_D), uniqueLocationID) + locationDescriptor.toTlv(ContextSpecificTag(TAG_LOCATION_DESCRIPTOR), this) + put(ContextSpecificTag(TAG_LOCATION_DESCRIPTOR_LAST_EDIT), locationDescriptorLastEdit) + put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex) + endStructure() + } + } + + companion object { + private const val TAG_UNIQUE_LOCATION_I_D = 0 + private const val TAG_LOCATION_DESCRIPTOR = 1 + private const val TAG_LOCATION_DESCRIPTOR_LAST_EDIT = 2 + private const val TAG_FABRIC_INDEX = 254 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): EcosystemInformationClusterEcosystemLocationStruct { + tlvReader.enterStructure(tlvTag) + val uniqueLocationID = tlvReader.getString(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_D)) + val locationDescriptor = + EcosystemInformationClusterHomeLocationStruct.fromTlv( + ContextSpecificTag(TAG_LOCATION_DESCRIPTOR), + tlvReader, + ) + val locationDescriptorLastEdit = + tlvReader.getULong(ContextSpecificTag(TAG_LOCATION_DESCRIPTOR_LAST_EDIT)) + val fabricIndex = tlvReader.getUInt(ContextSpecificTag(TAG_FABRIC_INDEX)) + + tlvReader.exitContainer() + + return EcosystemInformationClusterEcosystemLocationStruct( + uniqueLocationID, + locationDescriptor, + locationDescriptorLastEdit, + fabricIndex, + ) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt new file mode 100644 index 00000000000000..727c2276191f81 --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2023 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. + */ +package chip.devicecontroller.cluster.structs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterHomeLocationStruct( + val locationName: String, + val floorNumber: Int?, + val areaType: UInt?, +) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterHomeLocationStruct {\n") + append("\tlocationName : $locationName\n") + append("\tfloorNumber : $floorNumber\n") + append("\tareaType : $areaType\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_LOCATION_NAME), locationName) + if (floorNumber != null) { + put(ContextSpecificTag(TAG_FLOOR_NUMBER), floorNumber) + } else { + putNull(ContextSpecificTag(TAG_FLOOR_NUMBER)) + } + if (areaType != null) { + put(ContextSpecificTag(TAG_AREA_TYPE), areaType) + } else { + putNull(ContextSpecificTag(TAG_AREA_TYPE)) + } + endStructure() + } + } + + companion object { + private const val TAG_LOCATION_NAME = 0 + private const val TAG_FLOOR_NUMBER = 1 + private const val TAG_AREA_TYPE = 2 + + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): EcosystemInformationClusterHomeLocationStruct { + tlvReader.enterStructure(tlvTag) + val locationName = tlvReader.getString(ContextSpecificTag(TAG_LOCATION_NAME)) + val floorNumber = + if (!tlvReader.isNull()) { + tlvReader.getInt(ContextSpecificTag(TAG_FLOOR_NUMBER)) + } else { + tlvReader.getNull(ContextSpecificTag(TAG_FLOOR_NUMBER)) + null + } + val areaType = + if (!tlvReader.isNull()) { + tlvReader.getUInt(ContextSpecificTag(TAG_AREA_TYPE)) + } else { + tlvReader.getNull(ContextSpecificTag(TAG_AREA_TYPE)) + null + } + + tlvReader.exitContainer() + + return EcosystemInformationClusterHomeLocationStruct(locationName, floorNumber, areaType) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/EcosystemInformationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/EcosystemInformationCluster.kt new file mode 100644 index 00000000000000..5dfa4a7f8067ef --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/EcosystemInformationCluster.kt @@ -0,0 +1,969 @@ +/* + * + * Copyright (c) 2023 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. + */ + +package matter.controller.cluster.clusters + +import java.time.Duration +import java.util.logging.Level +import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.MatterController +import matter.controller.ReadData +import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState +import matter.controller.cluster.structs.* +import matter.controller.model.AttributePath +import matter.tlv.AnonymousTag +import matter.tlv.TlvReader + +class EcosystemInformationCluster( + private val controller: MatterController, + private val endpointId: UShort, +) { + class RemovedOnAttribute(val value: ULong?) + + sealed class RemovedOnAttributeSubscriptionState { + data class Success(val value: ULong?) : RemovedOnAttributeSubscriptionState() + + data class Error(val exception: Exception) : RemovedOnAttributeSubscriptionState() + + object SubscriptionEstablished : RemovedOnAttributeSubscriptionState() + } + + class DeviceDirectoryAttribute(val value: List) + + sealed class DeviceDirectoryAttributeSubscriptionState { + data class Success(val value: List) : + DeviceDirectoryAttributeSubscriptionState() + + data class Error(val exception: Exception) : DeviceDirectoryAttributeSubscriptionState() + + object SubscriptionEstablished : DeviceDirectoryAttributeSubscriptionState() + } + + class LocationDirectoryAttribute( + val value: List + ) + + sealed class LocationDirectoryAttributeSubscriptionState { + data class Success(val value: List) : + LocationDirectoryAttributeSubscriptionState() + + data class Error(val exception: Exception) : LocationDirectoryAttributeSubscriptionState() + + object SubscriptionEstablished : LocationDirectoryAttributeSubscriptionState() + } + + class GeneratedCommandListAttribute(val value: List) + + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + + class AcceptedCommandListAttribute(val value: List) + + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + + class EventListAttribute(val value: List) + + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + + class AttributeListAttribute(val value: List) + + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + + suspend fun readRemovedOnAttribute(): RemovedOnAttribute { + val ATTRIBUTE_ID: UInt = 0u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Removedon attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + return RemovedOnAttribute(decodedValue) + } + + suspend fun subscribeRemovedOnAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + RemovedOnAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Removedon attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(RemovedOnAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(RemovedOnAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readDeviceDirectoryAttribute(): DeviceDirectoryAttribute { + val ATTRIBUTE_ID: UInt = 1u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Devicedirectory attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(EcosystemInformationClusterEcosystemDeviceStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + return DeviceDirectoryAttribute(decodedValue) + } + + suspend fun subscribeDeviceDirectoryAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DeviceDirectoryAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Devicedirectory attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + EcosystemInformationClusterEcosystemDeviceStruct.fromTlv(AnonymousTag, tlvReader) + ) + } + tlvReader.exitContainer() + } + + emit(DeviceDirectoryAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(DeviceDirectoryAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readLocationDirectoryAttribute(): LocationDirectoryAttribute { + val ATTRIBUTE_ID: UInt = 2u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Locationdirectory attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(EcosystemInformationClusterEcosystemLocationStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + return LocationDirectoryAttribute(decodedValue) + } + + suspend fun subscribeLocationDirectoryAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LocationDirectoryAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Locationdirectory attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + EcosystemInformationClusterEcosystemLocationStruct.fromTlv( + AnonymousTag, + tlvReader, + ) + ) + } + tlvReader.exitContainer() + } + + emit(LocationDirectoryAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LocationDirectoryAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { + val ATTRIBUTE_ID: UInt = 65528u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Generatedcommandlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return GeneratedCommandListAttribute(decodedValue) + } + + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { + val ATTRIBUTE_ID: UInt = 65529u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Acceptedcommandlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return AcceptedCommandListAttribute(decodedValue) + } + + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readEventListAttribute(): EventListAttribute { + val ATTRIBUTE_ID: UInt = 65530u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Eventlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return EventListAttribute(decodedValue) + } + + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAttributeListAttribute(): AttributeListAttribute { + val ATTRIBUTE_ID: UInt = 65531u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Attributelist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return AttributeListAttribute(decodedValue) + } + + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readFeatureMapAttribute(): UInt { + val ATTRIBUTE_ID: UInt = 65532u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Featuremap attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readClusterRevisionAttribute(): UShort { + val ATTRIBUTE_ID: UInt = 65533u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Clusterrevision attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int, + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()), + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + + companion object { + private val logger = Logger.getLogger(EcosystemInformationCluster::class.java.name) + const val CLUSTER_ID: UInt = 1872u + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index 14ff82b93897cd..6b02ff0ca05bbb 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -56,6 +56,10 @@ matter_structs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/DishwasherModeClusterModeOptionStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/DishwasherModeClusterModeTagStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/DoorLockClusterCredentialStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ElectricalEnergyMeasurementClusterCumulativeEnergyResetStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ElectricalEnergyMeasurementClusterEnergyMeasurementStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ElectricalEnergyMeasurementClusterMeasurementAccuracyRangeStruct.kt", @@ -268,6 +272,7 @@ matter_clusters_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherAlarmCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherModeCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/EcosystemInformationCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalEnergyMeasurementCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalMeasurementCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalPowerMeasurementCluster.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt new file mode 100644 index 00000000000000..1ebb7b6abd3f60 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterDeviceTypeStruct.kt @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2023 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. + */ +package matter.controller.cluster.structs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterDeviceTypeStruct(val deviceType: UInt, val revision: UShort) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterDeviceTypeStruct {\n") + append("\tdeviceType : $deviceType\n") + append("\trevision : $revision\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_DEVICE_TYPE), deviceType) + put(ContextSpecificTag(TAG_REVISION), revision) + endStructure() + } + } + + companion object { + private const val TAG_DEVICE_TYPE = 0 + private const val TAG_REVISION = 1 + + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): EcosystemInformationClusterDeviceTypeStruct { + tlvReader.enterStructure(tlvTag) + val deviceType = tlvReader.getUInt(ContextSpecificTag(TAG_DEVICE_TYPE)) + val revision = tlvReader.getUShort(ContextSpecificTag(TAG_REVISION)) + + tlvReader.exitContainer() + + return EcosystemInformationClusterDeviceTypeStruct(deviceType, revision) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt new file mode 100644 index 00000000000000..0f04e02f973a58 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemDeviceStruct.kt @@ -0,0 +1,142 @@ +/* + * + * Copyright (c) 2023 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. + */ +package matter.controller.cluster.structs + +import java.util.Optional +import matter.controller.cluster.* +import matter.tlv.AnonymousTag +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterEcosystemDeviceStruct( + val deviceName: Optional, + val deviceNameLastEdit: Optional, + val bridgedEndpoint: UShort, + val originalEndpoint: UShort, + val deviceTypes: List, + val uniqueLocationIDs: List, + val uniqueLocationIDsLastEdit: ULong, + val fabricIndex: UByte, +) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterEcosystemDeviceStruct {\n") + append("\tdeviceName : $deviceName\n") + append("\tdeviceNameLastEdit : $deviceNameLastEdit\n") + append("\tbridgedEndpoint : $bridgedEndpoint\n") + append("\toriginalEndpoint : $originalEndpoint\n") + append("\tdeviceTypes : $deviceTypes\n") + append("\tuniqueLocationIDs : $uniqueLocationIDs\n") + append("\tuniqueLocationIDsLastEdit : $uniqueLocationIDsLastEdit\n") + append("\tfabricIndex : $fabricIndex\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + if (deviceName.isPresent) { + val optdeviceName = deviceName.get() + put(ContextSpecificTag(TAG_DEVICE_NAME), optdeviceName) + } + if (deviceNameLastEdit.isPresent) { + val optdeviceNameLastEdit = deviceNameLastEdit.get() + put(ContextSpecificTag(TAG_DEVICE_NAME_LAST_EDIT), optdeviceNameLastEdit) + } + put(ContextSpecificTag(TAG_BRIDGED_ENDPOINT), bridgedEndpoint) + put(ContextSpecificTag(TAG_ORIGINAL_ENDPOINT), originalEndpoint) + startArray(ContextSpecificTag(TAG_DEVICE_TYPES)) + for (item in deviceTypes.iterator()) { + item.toTlv(AnonymousTag, this) + } + endArray() + startArray(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS)) + for (item in uniqueLocationIDs.iterator()) { + put(AnonymousTag, item) + } + endArray() + put(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS_LAST_EDIT), uniqueLocationIDsLastEdit) + put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex) + endStructure() + } + } + + companion object { + private const val TAG_DEVICE_NAME = 0 + private const val TAG_DEVICE_NAME_LAST_EDIT = 1 + private const val TAG_BRIDGED_ENDPOINT = 2 + private const val TAG_ORIGINAL_ENDPOINT = 3 + private const val TAG_DEVICE_TYPES = 4 + private const val TAG_UNIQUE_LOCATION_I_DS = 5 + private const val TAG_UNIQUE_LOCATION_I_DS_LAST_EDIT = 6 + private const val TAG_FABRIC_INDEX = 254 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): EcosystemInformationClusterEcosystemDeviceStruct { + tlvReader.enterStructure(tlvTag) + val deviceName = + if (tlvReader.isNextTag(ContextSpecificTag(TAG_DEVICE_NAME))) { + Optional.of(tlvReader.getString(ContextSpecificTag(TAG_DEVICE_NAME))) + } else { + Optional.empty() + } + val deviceNameLastEdit = + if (tlvReader.isNextTag(ContextSpecificTag(TAG_DEVICE_NAME_LAST_EDIT))) { + Optional.of(tlvReader.getULong(ContextSpecificTag(TAG_DEVICE_NAME_LAST_EDIT))) + } else { + Optional.empty() + } + val bridgedEndpoint = tlvReader.getUShort(ContextSpecificTag(TAG_BRIDGED_ENDPOINT)) + val originalEndpoint = tlvReader.getUShort(ContextSpecificTag(TAG_ORIGINAL_ENDPOINT)) + val deviceTypes = + buildList { + tlvReader.enterArray(ContextSpecificTag(TAG_DEVICE_TYPES)) + while (!tlvReader.isEndOfContainer()) { + add(EcosystemInformationClusterDeviceTypeStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + val uniqueLocationIDs = + buildList { + tlvReader.enterArray(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS)) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + val uniqueLocationIDsLastEdit = + tlvReader.getULong(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_DS_LAST_EDIT)) + val fabricIndex = tlvReader.getUByte(ContextSpecificTag(TAG_FABRIC_INDEX)) + + tlvReader.exitContainer() + + return EcosystemInformationClusterEcosystemDeviceStruct( + deviceName, + deviceNameLastEdit, + bridgedEndpoint, + originalEndpoint, + deviceTypes, + uniqueLocationIDs, + uniqueLocationIDsLastEdit, + fabricIndex, + ) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt new file mode 100644 index 00000000000000..0c218223efe1d7 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterEcosystemLocationStruct.kt @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2023 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. + */ +package matter.controller.cluster.structs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterEcosystemLocationStruct( + val uniqueLocationID: String, + val locationDescriptor: EcosystemInformationClusterHomeLocationStruct, + val locationDescriptorLastEdit: ULong, + val fabricIndex: UByte, +) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterEcosystemLocationStruct {\n") + append("\tuniqueLocationID : $uniqueLocationID\n") + append("\tlocationDescriptor : $locationDescriptor\n") + append("\tlocationDescriptorLastEdit : $locationDescriptorLastEdit\n") + append("\tfabricIndex : $fabricIndex\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_D), uniqueLocationID) + locationDescriptor.toTlv(ContextSpecificTag(TAG_LOCATION_DESCRIPTOR), this) + put(ContextSpecificTag(TAG_LOCATION_DESCRIPTOR_LAST_EDIT), locationDescriptorLastEdit) + put(ContextSpecificTag(TAG_FABRIC_INDEX), fabricIndex) + endStructure() + } + } + + companion object { + private const val TAG_UNIQUE_LOCATION_I_D = 0 + private const val TAG_LOCATION_DESCRIPTOR = 1 + private const val TAG_LOCATION_DESCRIPTOR_LAST_EDIT = 2 + private const val TAG_FABRIC_INDEX = 254 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader, + ): EcosystemInformationClusterEcosystemLocationStruct { + tlvReader.enterStructure(tlvTag) + val uniqueLocationID = tlvReader.getString(ContextSpecificTag(TAG_UNIQUE_LOCATION_I_D)) + val locationDescriptor = + EcosystemInformationClusterHomeLocationStruct.fromTlv( + ContextSpecificTag(TAG_LOCATION_DESCRIPTOR), + tlvReader, + ) + val locationDescriptorLastEdit = + tlvReader.getULong(ContextSpecificTag(TAG_LOCATION_DESCRIPTOR_LAST_EDIT)) + val fabricIndex = tlvReader.getUByte(ContextSpecificTag(TAG_FABRIC_INDEX)) + + tlvReader.exitContainer() + + return EcosystemInformationClusterEcosystemLocationStruct( + uniqueLocationID, + locationDescriptor, + locationDescriptorLastEdit, + fabricIndex, + ) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt new file mode 100644 index 00000000000000..1ecbf220139dba --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/EcosystemInformationClusterHomeLocationStruct.kt @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2023 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. + */ +package matter.controller.cluster.structs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class EcosystemInformationClusterHomeLocationStruct( + val locationName: String, + val floorNumber: Short?, + val areaType: UByte?, +) { + override fun toString(): String = buildString { + append("EcosystemInformationClusterHomeLocationStruct {\n") + append("\tlocationName : $locationName\n") + append("\tfloorNumber : $floorNumber\n") + append("\tareaType : $areaType\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_LOCATION_NAME), locationName) + if (floorNumber != null) { + put(ContextSpecificTag(TAG_FLOOR_NUMBER), floorNumber) + } else { + putNull(ContextSpecificTag(TAG_FLOOR_NUMBER)) + } + if (areaType != null) { + put(ContextSpecificTag(TAG_AREA_TYPE), areaType) + } else { + putNull(ContextSpecificTag(TAG_AREA_TYPE)) + } + endStructure() + } + } + + companion object { + private const val TAG_LOCATION_NAME = 0 + private const val TAG_FLOOR_NUMBER = 1 + private const val TAG_AREA_TYPE = 2 + + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): EcosystemInformationClusterHomeLocationStruct { + tlvReader.enterStructure(tlvTag) + val locationName = tlvReader.getString(ContextSpecificTag(TAG_LOCATION_NAME)) + val floorNumber = + if (!tlvReader.isNull()) { + tlvReader.getShort(ContextSpecificTag(TAG_FLOOR_NUMBER)) + } else { + tlvReader.getNull(ContextSpecificTag(TAG_FLOOR_NUMBER)) + null + } + val areaType = + if (!tlvReader.isNull()) { + tlvReader.getUByte(ContextSpecificTag(TAG_AREA_TYPE)) + } else { + tlvReader.getNull(ContextSpecificTag(TAG_AREA_TYPE)) + null + } + + tlvReader.exitContainer() + + return EcosystemInformationClusterHomeLocationStruct(locationName, floorNumber, areaType) + } + } +} diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 183a61a505c875..20a00dd454ae7f 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -42666,6 +42666,461 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } break; } + case app::Clusters::EcosystemInformation::Id: { + using namespace app::Clusters::EcosystemInformation; + switch (aPath.mAttributeId) + { + case Attributes::RemovedOn::Id: { + using TypeInfo = Attributes::RemovedOn::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + if (cppValue.IsNull()) + { + value = nullptr; + } + else + { + std::string valueClassName = "java/lang/Long"; + std::string valueCtorSignature = "(J)V"; + jlong jnivalue = static_cast(cppValue.Value()); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), + jnivalue, value); + } + return value; + } + case Attributes::DeviceDirectory::Id: { + using TypeInfo = Attributes::DeviceDirectory::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + jobject newElement_0_deviceName; + if (!entry_0.deviceName.HasValue()) + { + chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_0_deviceName); + } + else + { + jobject newElement_0_deviceNameInsideOptional; + LogErrorOnFailure(chip::JniReferences::GetInstance().CharToStringUTF(entry_0.deviceName.Value(), + newElement_0_deviceNameInsideOptional)); + chip::JniReferences::GetInstance().CreateOptional(newElement_0_deviceNameInsideOptional, + newElement_0_deviceName); + } + jobject newElement_0_deviceNameLastEdit; + if (!entry_0.deviceNameLastEdit.HasValue()) + { + chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_0_deviceNameLastEdit); + } + else + { + jobject newElement_0_deviceNameLastEditInsideOptional; + std::string newElement_0_deviceNameLastEditInsideOptionalClassName = "java/lang/Long"; + std::string newElement_0_deviceNameLastEditInsideOptionalCtorSignature = "(J)V"; + jlong jninewElement_0_deviceNameLastEditInsideOptional = static_cast(entry_0.deviceNameLastEdit.Value()); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_deviceNameLastEditInsideOptionalClassName.c_str(), + newElement_0_deviceNameLastEditInsideOptionalCtorSignature.c_str(), + jninewElement_0_deviceNameLastEditInsideOptional, newElement_0_deviceNameLastEditInsideOptional); + chip::JniReferences::GetInstance().CreateOptional(newElement_0_deviceNameLastEditInsideOptional, + newElement_0_deviceNameLastEdit); + } + jobject newElement_0_bridgedEndpoint; + std::string newElement_0_bridgedEndpointClassName = "java/lang/Integer"; + std::string newElement_0_bridgedEndpointCtorSignature = "(I)V"; + jint jninewElement_0_bridgedEndpoint = static_cast(entry_0.bridgedEndpoint); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_bridgedEndpointClassName.c_str(), newElement_0_bridgedEndpointCtorSignature.c_str(), + jninewElement_0_bridgedEndpoint, newElement_0_bridgedEndpoint); + jobject newElement_0_originalEndpoint; + std::string newElement_0_originalEndpointClassName = "java/lang/Integer"; + std::string newElement_0_originalEndpointCtorSignature = "(I)V"; + jint jninewElement_0_originalEndpoint = static_cast(entry_0.originalEndpoint); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_originalEndpointClassName.c_str(), newElement_0_originalEndpointCtorSignature.c_str(), + jninewElement_0_originalEndpoint, newElement_0_originalEndpoint); + jobject newElement_0_deviceTypes; + chip::JniReferences::GetInstance().CreateArrayList(newElement_0_deviceTypes); + + auto iter_newElement_0_deviceTypes_2 = entry_0.deviceTypes.begin(); + while (iter_newElement_0_deviceTypes_2.Next()) + { + auto & entry_2 = iter_newElement_0_deviceTypes_2.GetValue(); + jobject newElement_2; + jobject newElement_2_deviceType; + std::string newElement_2_deviceTypeClassName = "java/lang/Long"; + std::string newElement_2_deviceTypeCtorSignature = "(J)V"; + jlong jninewElement_2_deviceType = static_cast(entry_2.deviceType); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_2_deviceTypeClassName.c_str(), newElement_2_deviceTypeCtorSignature.c_str(), + jninewElement_2_deviceType, newElement_2_deviceType); + jobject newElement_2_revision; + std::string newElement_2_revisionClassName = "java/lang/Integer"; + std::string newElement_2_revisionCtorSignature = "(I)V"; + jint jninewElement_2_revision = static_cast(entry_2.revision); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_2_revisionClassName.c_str(), + newElement_2_revisionCtorSignature.c_str(), + jninewElement_2_revision, newElement_2_revision); + + jclass deviceTypeStructStructClass_3; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipStructs$EcosystemInformationClusterDeviceTypeStruct", + deviceTypeStructStructClass_3); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Could not find class ChipStructs$EcosystemInformationClusterDeviceTypeStruct"); + return nullptr; + } + + jmethodID deviceTypeStructStructCtor_3; + err = chip::JniReferences::GetInstance().FindMethod(env, deviceTypeStructStructClass_3, "", + "(Ljava/lang/Long;Ljava/lang/Integer;)V", + &deviceTypeStructStructCtor_3); + if (err != CHIP_NO_ERROR || deviceTypeStructStructCtor_3 == nullptr) + { + ChipLogError(Zcl, "Could not find ChipStructs$EcosystemInformationClusterDeviceTypeStruct constructor"); + return nullptr; + } + + newElement_2 = env->NewObject(deviceTypeStructStructClass_3, deviceTypeStructStructCtor_3, + newElement_2_deviceType, newElement_2_revision); + chip::JniReferences::GetInstance().AddToList(newElement_0_deviceTypes, newElement_2); + } + jobject newElement_0_uniqueLocationIDs; + chip::JniReferences::GetInstance().CreateArrayList(newElement_0_uniqueLocationIDs); + + auto iter_newElement_0_uniqueLocationIDs_2 = entry_0.uniqueLocationIDs.begin(); + while (iter_newElement_0_uniqueLocationIDs_2.Next()) + { + auto & entry_2 = iter_newElement_0_uniqueLocationIDs_2.GetValue(); + jobject newElement_2; + LogErrorOnFailure(chip::JniReferences::GetInstance().CharToStringUTF(entry_2, newElement_2)); + chip::JniReferences::GetInstance().AddToList(newElement_0_uniqueLocationIDs, newElement_2); + } + jobject newElement_0_uniqueLocationIDsLastEdit; + std::string newElement_0_uniqueLocationIDsLastEditClassName = "java/lang/Long"; + std::string newElement_0_uniqueLocationIDsLastEditCtorSignature = "(J)V"; + jlong jninewElement_0_uniqueLocationIDsLastEdit = static_cast(entry_0.uniqueLocationIDsLastEdit); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_uniqueLocationIDsLastEditClassName.c_str(), + newElement_0_uniqueLocationIDsLastEditCtorSignature.c_str(), jninewElement_0_uniqueLocationIDsLastEdit, + newElement_0_uniqueLocationIDsLastEdit); + jobject newElement_0_fabricIndex; + std::string newElement_0_fabricIndexClassName = "java/lang/Integer"; + std::string newElement_0_fabricIndexCtorSignature = "(I)V"; + jint jninewElement_0_fabricIndex = static_cast(entry_0.fabricIndex); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_fabricIndexClassName.c_str(), + newElement_0_fabricIndexCtorSignature.c_str(), + jninewElement_0_fabricIndex, newElement_0_fabricIndex); + + jclass ecosystemDeviceStructStructClass_1; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipStructs$EcosystemInformationClusterEcosystemDeviceStruct", + ecosystemDeviceStructStructClass_1); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Could not find class ChipStructs$EcosystemInformationClusterEcosystemDeviceStruct"); + return nullptr; + } + + jmethodID ecosystemDeviceStructStructCtor_1; + err = chip::JniReferences::GetInstance().FindMethod( + env, ecosystemDeviceStructStructClass_1, "", + "(Ljava/util/Optional;Ljava/util/Optional;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/util/ArrayList;Ljava/" + "util/ArrayList;Ljava/lang/Long;Ljava/lang/Integer;)V", + &ecosystemDeviceStructStructCtor_1); + if (err != CHIP_NO_ERROR || ecosystemDeviceStructStructCtor_1 == nullptr) + { + ChipLogError(Zcl, "Could not find ChipStructs$EcosystemInformationClusterEcosystemDeviceStruct constructor"); + return nullptr; + } + + newElement_0 = + env->NewObject(ecosystemDeviceStructStructClass_1, ecosystemDeviceStructStructCtor_1, newElement_0_deviceName, + newElement_0_deviceNameLastEdit, newElement_0_bridgedEndpoint, newElement_0_originalEndpoint, + newElement_0_deviceTypes, newElement_0_uniqueLocationIDs, newElement_0_uniqueLocationIDsLastEdit, + newElement_0_fabricIndex); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::LocationDirectory::Id: { + using TypeInfo = Attributes::LocationDirectory::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + jobject newElement_0_uniqueLocationID; + LogErrorOnFailure( + chip::JniReferences::GetInstance().CharToStringUTF(entry_0.uniqueLocationID, newElement_0_uniqueLocationID)); + jobject newElement_0_locationDescriptor; + jobject newElement_0_locationDescriptor_locationName; + LogErrorOnFailure(chip::JniReferences::GetInstance().CharToStringUTF(entry_0.locationDescriptor.locationName, + newElement_0_locationDescriptor_locationName)); + jobject newElement_0_locationDescriptor_floorNumber; + if (entry_0.locationDescriptor.floorNumber.IsNull()) + { + newElement_0_locationDescriptor_floorNumber = nullptr; + } + else + { + std::string newElement_0_locationDescriptor_floorNumberClassName = "java/lang/Integer"; + std::string newElement_0_locationDescriptor_floorNumberCtorSignature = "(I)V"; + jint jninewElement_0_locationDescriptor_floorNumber = + static_cast(entry_0.locationDescriptor.floorNumber.Value()); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_locationDescriptor_floorNumberClassName.c_str(), + newElement_0_locationDescriptor_floorNumberCtorSignature.c_str(), + jninewElement_0_locationDescriptor_floorNumber, newElement_0_locationDescriptor_floorNumber); + } + jobject newElement_0_locationDescriptor_areaType; + if (entry_0.locationDescriptor.areaType.IsNull()) + { + newElement_0_locationDescriptor_areaType = nullptr; + } + else + { + std::string newElement_0_locationDescriptor_areaTypeClassName = "java/lang/Integer"; + std::string newElement_0_locationDescriptor_areaTypeCtorSignature = "(I)V"; + jint jninewElement_0_locationDescriptor_areaType = + static_cast(entry_0.locationDescriptor.areaType.Value()); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_locationDescriptor_areaTypeClassName.c_str(), + newElement_0_locationDescriptor_areaTypeCtorSignature.c_str(), jninewElement_0_locationDescriptor_areaType, + newElement_0_locationDescriptor_areaType); + } + + jclass homeLocationStructStructClass_2; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipStructs$EcosystemInformationClusterHomeLocationStruct", + homeLocationStructStructClass_2); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Could not find class ChipStructs$EcosystemInformationClusterHomeLocationStruct"); + return nullptr; + } + + jmethodID homeLocationStructStructCtor_2; + err = chip::JniReferences::GetInstance().FindMethod(env, homeLocationStructStructClass_2, "", + "(Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;)V", + &homeLocationStructStructCtor_2); + if (err != CHIP_NO_ERROR || homeLocationStructStructCtor_2 == nullptr) + { + ChipLogError(Zcl, "Could not find ChipStructs$EcosystemInformationClusterHomeLocationStruct constructor"); + return nullptr; + } + + newElement_0_locationDescriptor = env->NewObject( + homeLocationStructStructClass_2, homeLocationStructStructCtor_2, newElement_0_locationDescriptor_locationName, + newElement_0_locationDescriptor_floorNumber, newElement_0_locationDescriptor_areaType); + jobject newElement_0_locationDescriptorLastEdit; + std::string newElement_0_locationDescriptorLastEditClassName = "java/lang/Long"; + std::string newElement_0_locationDescriptorLastEditCtorSignature = "(J)V"; + jlong jninewElement_0_locationDescriptorLastEdit = static_cast(entry_0.locationDescriptorLastEdit); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_locationDescriptorLastEditClassName.c_str(), + newElement_0_locationDescriptorLastEditCtorSignature.c_str(), jninewElement_0_locationDescriptorLastEdit, + newElement_0_locationDescriptorLastEdit); + jobject newElement_0_fabricIndex; + std::string newElement_0_fabricIndexClassName = "java/lang/Integer"; + std::string newElement_0_fabricIndexCtorSignature = "(I)V"; + jint jninewElement_0_fabricIndex = static_cast(entry_0.fabricIndex); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_fabricIndexClassName.c_str(), + newElement_0_fabricIndexCtorSignature.c_str(), + jninewElement_0_fabricIndex, newElement_0_fabricIndex); + + jclass ecosystemLocationStructStructClass_1; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipStructs$EcosystemInformationClusterEcosystemLocationStruct", + ecosystemLocationStructStructClass_1); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Could not find class ChipStructs$EcosystemInformationClusterEcosystemLocationStruct"); + return nullptr; + } + + jmethodID ecosystemLocationStructStructCtor_1; + err = chip::JniReferences::GetInstance().FindMethod( + env, ecosystemLocationStructStructClass_1, "", + "(Ljava/lang/String;Lchip/devicecontroller/ChipStructs$EcosystemInformationClusterHomeLocationStruct;Ljava/" + "lang/Long;Ljava/lang/Integer;)V", + &ecosystemLocationStructStructCtor_1); + if (err != CHIP_NO_ERROR || ecosystemLocationStructStructCtor_1 == nullptr) + { + ChipLogError(Zcl, "Could not find ChipStructs$EcosystemInformationClusterEcosystemLocationStruct constructor"); + return nullptr; + } + + newElement_0 = env->NewObject(ecosystemLocationStructStructClass_1, ecosystemLocationStructStructCtor_1, + newElement_0_uniqueLocationID, newElement_0_locationDescriptor, + newElement_0_locationDescriptorLastEdit, newElement_0_fabricIndex); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::GeneratedCommandList::Id: { + using TypeInfo = Attributes::GeneratedCommandList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::AcceptedCommandList::Id: { + using TypeInfo = Attributes::AcceptedCommandList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::EventList::Id: { + using TypeInfo = Attributes::EventList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::AttributeList::Id: { + using TypeInfo = Attributes::AttributeList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::FeatureMap::Id: { + using TypeInfo = Attributes::FeatureMap::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Long"; + std::string valueCtorSignature = "(J)V"; + jlong jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), + jnivalue, value); + return value; + } + case Attributes::ClusterRevision::Id: { + using TypeInfo = Attributes::ClusterRevision::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } + default: + *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; + break; + } + break; + } case app::Clusters::CommissionerControl::Id: { using namespace app::Clusters::CommissionerControl; switch (aPath.mAttributeId) diff --git a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp index 8d7826aed4d310..42868bfd0465b1 100644 --- a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp @@ -7979,6 +7979,16 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & } break; } + case app::Clusters::EcosystemInformation::Id: { + using namespace app::Clusters::EcosystemInformation; + switch (aPath.mEventId) + { + default: + *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; + break; + } + break; + } case app::Clusters::CommissionerControl::Id: { using namespace app::Clusters::CommissionerControl; switch (aPath.mEventId) diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index c9f559f9f61915..6621bbc4bea2a6 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -13275,6 +13275,68 @@ class ChipClusters: }, }, } + _ECOSYSTEM_INFORMATION_CLUSTER_INFO = { + "clusterName": "EcosystemInformation", + "clusterId": 0x00000750, + "commands": { + }, + "attributes": { + 0x00000000: { + "attributeName": "RemovedOn", + "attributeId": 0x00000000, + "type": "int", + "reportable": True, + }, + 0x00000001: { + "attributeName": "DeviceDirectory", + "attributeId": 0x00000001, + "type": "", + "reportable": True, + }, + 0x00000002: { + "attributeName": "LocationDirectory", + "attributeId": 0x00000002, + "type": "", + "reportable": True, + }, + 0x0000FFF8: { + "attributeName": "GeneratedCommandList", + "attributeId": 0x0000FFF8, + "type": "int", + "reportable": True, + }, + 0x0000FFF9: { + "attributeName": "AcceptedCommandList", + "attributeId": 0x0000FFF9, + "type": "int", + "reportable": True, + }, + 0x0000FFFA: { + "attributeName": "EventList", + "attributeId": 0x0000FFFA, + "type": "int", + "reportable": True, + }, + 0x0000FFFB: { + "attributeName": "AttributeList", + "attributeId": 0x0000FFFB, + "type": "int", + "reportable": True, + }, + 0x0000FFFC: { + "attributeName": "FeatureMap", + "attributeId": 0x0000FFFC, + "type": "int", + "reportable": True, + }, + 0x0000FFFD: { + "attributeName": "ClusterRevision", + "attributeId": 0x0000FFFD, + "type": "int", + "reportable": True, + }, + }, + } _COMMISSIONER_CONTROL_CLUSTER_INFO = { "clusterName": "CommissionerControl", "clusterId": 0x00000751, @@ -15257,6 +15319,7 @@ class ChipClusters: 0x0000050E: _ACCOUNT_LOGIN_CLUSTER_INFO, 0x0000050F: _CONTENT_CONTROL_CLUSTER_INFO, 0x00000510: _CONTENT_APP_OBSERVER_CLUSTER_INFO, + 0x00000750: _ECOSYSTEM_INFORMATION_CLUSTER_INFO, 0x00000751: _COMMISSIONER_CONTROL_CLUSTER_INFO, 0x00000B04: _ELECTRICAL_MEASUREMENT_CLUSTER_INFO, 0xFFF1FC05: _UNIT_TESTING_CLUSTER_INFO, @@ -15385,6 +15448,7 @@ class ChipClusters: "AccountLogin": _ACCOUNT_LOGIN_CLUSTER_INFO, "ContentControl": _CONTENT_CONTROL_CLUSTER_INFO, "ContentAppObserver": _CONTENT_APP_OBSERVER_CLUSTER_INFO, + "EcosystemInformation": _ECOSYSTEM_INFORMATION_CLUSTER_INFO, "CommissionerControl": _COMMISSIONER_CONTROL_CLUSTER_INFO, "ElectricalMeasurement": _ELECTRICAL_MEASUREMENT_CLUSTER_INFO, "UnitTesting": _UNIT_TESTING_CLUSTER_INFO, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 654a6d292a6910..2ad8d02fb1aae2 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -46633,6 +46633,355 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'uint' = 0 +@dataclass +class EcosystemInformation(Cluster): + id: typing.ClassVar[int] = 0x00000750 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="removedOn", Tag=0x00000000, Type=typing.Union[None, Nullable, uint]), + ClusterObjectFieldDescriptor(Label="deviceDirectory", Tag=0x00000001, Type=typing.List[EcosystemInformation.Structs.EcosystemDeviceStruct]), + ClusterObjectFieldDescriptor(Label="locationDirectory", Tag=0x00000002, Type=typing.List[EcosystemInformation.Structs.EcosystemLocationStruct]), + ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="attributeList", Tag=0x0000FFFB, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="featureMap", Tag=0x0000FFFC, Type=uint), + ClusterObjectFieldDescriptor(Label="clusterRevision", Tag=0x0000FFFD, Type=uint), + ]) + + removedOn: 'typing.Union[None, Nullable, uint]' = None + deviceDirectory: 'typing.List[EcosystemInformation.Structs.EcosystemDeviceStruct]' = None + locationDirectory: 'typing.List[EcosystemInformation.Structs.EcosystemLocationStruct]' = None + generatedCommandList: 'typing.List[uint]' = None + acceptedCommandList: 'typing.List[uint]' = None + eventList: 'typing.List[uint]' = None + attributeList: 'typing.List[uint]' = None + featureMap: 'uint' = None + clusterRevision: 'uint' = None + + class Enums: + class AreaTypeTag(MatterIntEnum): + kAisle = 0x00 + kAttic = 0x01 + kBackDoor = 0x02 + kBackYard = 0x03 + kBalcony = 0x04 + kBallroom = 0x05 + kBathroom = 0x06 + kBedroom = 0x07 + kBorder = 0x08 + kBoxroom = 0x09 + kBreakfastRoom = 0x0A + kCarport = 0x0B + kCellar = 0x0C + kCloakroom = 0x0D + kCloset = 0x0E + kConservatory = 0x0F + kCorridor = 0x10 + kCraftRoom = 0x11 + kCupboard = 0x12 + kDeck = 0x13 + kDen = 0x14 + kDining = 0x15 + kDrawingRoom = 0x16 + kDressingRoom = 0x17 + kDriveway = 0x18 + kElevator = 0x19 + kEnsuite = 0x1A + kEntrance = 0x1B + kEntryway = 0x1C + kFamilyRoom = 0x1D + kFoyer = 0x1E + kFrontDoor = 0x1F + kFrontYard = 0x20 + kGameRoom = 0x21 + kGarage = 0x22 + kGarageDoor = 0x23 + kGarden = 0x24 + kGardenDoor = 0x25 + kGuestBathroom = 0x26 + kGuestBedroom = 0x27 + kGuestRestroom = 0x28 + kGuestRoom = 0x29 + kGym = 0x2A + kHallway = 0x2B + kHearthRoom = 0x2C + kKidsRoom = 0x2D + kKidsBedroom = 0x2E + kKitchen = 0x2F + kLarder = 0x30 + kLaundryRoom = 0x31 + kLawn = 0x32 + kLibrary = 0x33 + kLivingRoom = 0x34 + kLounge = 0x35 + kMediaTvRoom = 0x36 + kMudRoom = 0x37 + kMusicRoom = 0x38 + kNursery = 0x39 + kOffice = 0x3A + kOutdoorKitchen = 0x3B + kOutside = 0x3C + kPantry = 0x3D + kParkingLot = 0x3E + kParlor = 0x3F + kPatio = 0x40 + kPlayRoom = 0x41 + kPoolRoom = 0x42 + kPorch = 0x43 + kPrimaryBathroom = 0x44 + kPrimaryBedroom = 0x45 + kRamp = 0x46 + kReceptionRoom = 0x47 + kRecreationRoom = 0x48 + kRestroom = 0x49 + kRoof = 0x4A + kSauna = 0x4B + kScullery = 0x4C + kSewingRoom = 0x4D + kShed = 0x4E + kSideDoor = 0x4F + kSideYard = 0x50 + kSittingRoom = 0x51 + kSnug = 0x52 + kSpa = 0x53 + kStaircase = 0x54 + kSteamRoom = 0x55 + kStorageRoom = 0x56 + kStudio = 0x57 + kStudy = 0x58 + kSunRoom = 0x59 + kSwimmingPool = 0x5A + kTerrace = 0x5B + kUtilityRoom = 0x5C + kWard = 0x5D + kWorkshop = 0x5E + # All received enum values that are not listed above will be mapped + # to kUnknownEnumValue. This is a helper enum value that should only + # be used by code to process how it handles receiving and unknown + # enum value. This specific should never be transmitted. + kUnknownEnumValue = 95, + + class Structs: + @dataclass + class HomeLocationStruct(ClusterObject): + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="locationName", Tag=0, Type=str), + ClusterObjectFieldDescriptor(Label="floorNumber", Tag=1, Type=typing.Union[Nullable, int]), + ClusterObjectFieldDescriptor(Label="areaType", Tag=2, Type=typing.Union[Nullable, EcosystemInformation.Enums.AreaTypeTag]), + ]) + + locationName: 'str' = "" + floorNumber: 'typing.Union[Nullable, int]' = NullValue + areaType: 'typing.Union[Nullable, EcosystemInformation.Enums.AreaTypeTag]' = NullValue + + @dataclass + class EcosystemLocationStruct(ClusterObject): + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="uniqueLocationID", Tag=0, Type=str), + ClusterObjectFieldDescriptor(Label="locationDescriptor", Tag=1, Type=EcosystemInformation.Structs.HomeLocationStruct), + ClusterObjectFieldDescriptor(Label="locationDescriptorLastEdit", Tag=2, Type=uint), + ClusterObjectFieldDescriptor(Label="fabricIndex", Tag=254, Type=uint), + ]) + + uniqueLocationID: 'str' = "" + locationDescriptor: 'EcosystemInformation.Structs.HomeLocationStruct' = field(default_factory=lambda: EcosystemInformation.Structs.HomeLocationStruct()) + locationDescriptorLastEdit: 'uint' = 0 + fabricIndex: 'uint' = 0 + + @dataclass + class DeviceTypeStruct(ClusterObject): + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="deviceType", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="revision", Tag=1, Type=uint), + ]) + + deviceType: 'uint' = 0 + revision: 'uint' = 0 + + @dataclass + class EcosystemDeviceStruct(ClusterObject): + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="deviceName", Tag=0, Type=typing.Optional[str]), + ClusterObjectFieldDescriptor(Label="deviceNameLastEdit", Tag=1, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="bridgedEndpoint", Tag=2, Type=uint), + ClusterObjectFieldDescriptor(Label="originalEndpoint", Tag=3, Type=uint), + ClusterObjectFieldDescriptor(Label="deviceTypes", Tag=4, Type=typing.List[EcosystemInformation.Structs.DeviceTypeStruct]), + ClusterObjectFieldDescriptor(Label="uniqueLocationIDs", Tag=5, Type=typing.List[str]), + ClusterObjectFieldDescriptor(Label="uniqueLocationIDsLastEdit", Tag=6, Type=uint), + ClusterObjectFieldDescriptor(Label="fabricIndex", Tag=254, Type=uint), + ]) + + deviceName: 'typing.Optional[str]' = None + deviceNameLastEdit: 'typing.Optional[uint]' = None + bridgedEndpoint: 'uint' = 0 + originalEndpoint: 'uint' = 0 + deviceTypes: 'typing.List[EcosystemInformation.Structs.DeviceTypeStruct]' = field(default_factory=lambda: []) + uniqueLocationIDs: 'typing.List[str]' = field(default_factory=lambda: []) + uniqueLocationIDsLastEdit: 'uint' = 0 + fabricIndex: 'uint' = 0 + + class Attributes: + @dataclass + class RemovedOn(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000000 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Union[None, Nullable, uint]) + + value: 'typing.Union[None, Nullable, uint]' = None + + @dataclass + class DeviceDirectory(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000001 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[EcosystemInformation.Structs.EcosystemDeviceStruct]) + + value: 'typing.List[EcosystemInformation.Structs.EcosystemDeviceStruct]' = field(default_factory=lambda: []) + + @dataclass + class LocationDirectory(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000002 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[EcosystemInformation.Structs.EcosystemLocationStruct]) + + value: 'typing.List[EcosystemInformation.Structs.EcosystemLocationStruct]' = field(default_factory=lambda: []) + + @dataclass + class GeneratedCommandList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFF8 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class AcceptedCommandList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFF9 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class EventList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFA + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class AttributeList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFB + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class FeatureMap(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFC + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + @dataclass + class ClusterRevision(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000750 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFD + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + @dataclass class CommissionerControl(Cluster): id: typing.ClassVar[int] = 0x00000751 diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm index 0d2f7bca464902..204d15937b23ca 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm @@ -6035,6 +6035,42 @@ static BOOL AttributeIsSpecifiedInContentAppObserverCluster(AttributeId aAttribu } } } +static BOOL AttributeIsSpecifiedInEcosystemInformationCluster(AttributeId aAttributeId) +{ + using namespace Clusters::EcosystemInformation; + switch (aAttributeId) { + case Attributes::RemovedOn::Id: { + return YES; + } + case Attributes::DeviceDirectory::Id: { + return YES; + } + case Attributes::LocationDirectory::Id: { + return YES; + } + case Attributes::GeneratedCommandList::Id: { + return YES; + } + case Attributes::AcceptedCommandList::Id: { + return YES; + } + case Attributes::EventList::Id: { + return YES; + } + case Attributes::AttributeList::Id: { + return YES; + } + case Attributes::FeatureMap::Id: { + return YES; + } + case Attributes::ClusterRevision::Id: { + return YES; + } + default: { + return NO; + } + } +} static BOOL AttributeIsSpecifiedInCommissionerControlCluster(AttributeId aAttributeId) { using namespace Clusters::CommissionerControl; @@ -7137,6 +7173,9 @@ BOOL MTRAttributeIsSpecified(ClusterId aClusterId, AttributeId aAttributeId) case Clusters::ContentAppObserver::Id: { return AttributeIsSpecifiedInContentAppObserverCluster(aAttributeId); } + case Clusters::EcosystemInformation::Id: { + return AttributeIsSpecifiedInEcosystemInformationCluster(aAttributeId); + } case Clusters::CommissionerControl::Id: { return AttributeIsSpecifiedInCommissionerControlCluster(aAttributeId); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 8ce69c91d5ae56..c20bade614d8e3 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -17037,6 +17037,168 @@ static id _Nullable DecodeAttributeValueForContentAppObserverCluster(AttributeId *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; return nil; } +static id _Nullable DecodeAttributeValueForEcosystemInformationCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +{ + using namespace Clusters::EcosystemInformation; + switch (aAttributeId) { + case Attributes::RemovedOn::Id: { + using TypeInfo = Attributes::RemovedOn::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nullable value; + if (cppValue.IsNull()) { + value = nil; + } else { + value = [NSNumber numberWithUnsignedLongLong:cppValue.Value()]; + } + return value; + } + case Attributes::DeviceDirectory::Id: { + using TypeInfo = Attributes::DeviceDirectory::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSArray * _Nonnull value; + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + auto iter_0 = cppValue.begin(); + while (iter_0.Next()) { + auto & entry_0 = iter_0.GetValue(); + MTREcosystemInformationClusterEcosystemDeviceStruct * newElement_0; + newElement_0 = [MTREcosystemInformationClusterEcosystemDeviceStruct new]; + if (entry_0.deviceName.HasValue()) { + newElement_0.deviceName = AsString(entry_0.deviceName.Value()); + if (newElement_0.deviceName == nil) { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + *aError = err; + return nil; + } + } else { + newElement_0.deviceName = nil; + } + if (entry_0.deviceNameLastEdit.HasValue()) { + newElement_0.deviceNameLastEdit = [NSNumber numberWithUnsignedLongLong:entry_0.deviceNameLastEdit.Value()]; + } else { + newElement_0.deviceNameLastEdit = nil; + } + newElement_0.bridgedEndpoint = [NSNumber numberWithUnsignedShort:entry_0.bridgedEndpoint]; + newElement_0.originalEndpoint = [NSNumber numberWithUnsignedShort:entry_0.originalEndpoint]; + { // Scope for our temporary variables + auto * array_2 = [NSMutableArray new]; + auto iter_2 = entry_0.deviceTypes.begin(); + while (iter_2.Next()) { + auto & entry_2 = iter_2.GetValue(); + MTREcosystemInformationClusterDeviceTypeStruct * newElement_2; + newElement_2 = [MTREcosystemInformationClusterDeviceTypeStruct new]; + newElement_2.deviceType = [NSNumber numberWithUnsignedInt:entry_2.deviceType]; + newElement_2.revision = [NSNumber numberWithUnsignedShort:entry_2.revision]; + [array_2 addObject:newElement_2]; + } + CHIP_ERROR err = iter_2.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; + } + newElement_0.deviceTypes = array_2; + } + { // Scope for our temporary variables + auto * array_2 = [NSMutableArray new]; + auto iter_2 = entry_0.uniqueLocationIDs.begin(); + while (iter_2.Next()) { + auto & entry_2 = iter_2.GetValue(); + NSString * newElement_2; + newElement_2 = AsString(entry_2); + if (newElement_2 == nil) { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + *aError = err; + return nil; + } + [array_2 addObject:newElement_2]; + } + CHIP_ERROR err = iter_2.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; + } + newElement_0.uniqueLocationIDs = array_2; + } + newElement_0.uniqueLocationIDsLastEdit = [NSNumber numberWithUnsignedLongLong:entry_0.uniqueLocationIDsLastEdit]; + newElement_0.fabricIndex = [NSNumber numberWithUnsignedChar:entry_0.fabricIndex]; + [array_0 addObject:newElement_0]; + } + CHIP_ERROR err = iter_0.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; + } + value = array_0; + } + return value; + } + case Attributes::LocationDirectory::Id: { + using TypeInfo = Attributes::LocationDirectory::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSArray * _Nonnull value; + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + auto iter_0 = cppValue.begin(); + while (iter_0.Next()) { + auto & entry_0 = iter_0.GetValue(); + MTREcosystemInformationClusterEcosystemLocationStruct * newElement_0; + newElement_0 = [MTREcosystemInformationClusterEcosystemLocationStruct new]; + newElement_0.uniqueLocationID = AsString(entry_0.uniqueLocationID); + if (newElement_0.uniqueLocationID == nil) { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + *aError = err; + return nil; + } + newElement_0.locationDescriptor = [MTREcosystemInformationClusterHomeLocationStruct new]; + newElement_0.locationDescriptor.locationName = AsString(entry_0.locationDescriptor.locationName); + if (newElement_0.locationDescriptor.locationName == nil) { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + *aError = err; + return nil; + } + if (entry_0.locationDescriptor.floorNumber.IsNull()) { + newElement_0.locationDescriptor.floorNumber = nil; + } else { + newElement_0.locationDescriptor.floorNumber = [NSNumber numberWithShort:entry_0.locationDescriptor.floorNumber.Value()]; + } + if (entry_0.locationDescriptor.areaType.IsNull()) { + newElement_0.locationDescriptor.areaType = nil; + } else { + newElement_0.locationDescriptor.areaType = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.locationDescriptor.areaType.Value())]; + } + newElement_0.locationDescriptorLastEdit = [NSNumber numberWithUnsignedLongLong:entry_0.locationDescriptorLastEdit]; + newElement_0.fabricIndex = [NSNumber numberWithUnsignedChar:entry_0.fabricIndex]; + [array_0 addObject:newElement_0]; + } + CHIP_ERROR err = iter_0.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; + } + value = array_0; + } + return value; + } + default: { + break; + } + } + + *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; + return nil; +} static id _Nullable DecodeAttributeValueForCommissionerControlCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { using namespace Clusters::CommissionerControl; @@ -20284,6 +20446,9 @@ id _Nullable MTRDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::T case Clusters::ContentAppObserver::Id: { return DecodeAttributeValueForContentAppObserverCluster(aPath.mAttributeId, aReader, aError); } + case Clusters::EcosystemInformation::Id: { + return DecodeAttributeValueForEcosystemInformationCluster(aPath.mAttributeId, aReader, aError); + } case Clusters::CommissionerControl::Id: { return DecodeAttributeValueForCommissionerControlCluster(aPath.mAttributeId, aReader, aError); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 7c3e36f0797323..dd0eecc0006f2a 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -15077,6 +15077,85 @@ MTR_PROVISIONALLY_AVAILABLE @end +/** + * Cluster Ecosystem Information + * + * Provides extended device information for all the logical devices represented by a Bridged Node. + */ +MTR_PROVISIONALLY_AVAILABLE +@interface MTRBaseClusterEcosystemInformation : MTRGenericBaseCluster + +- (void)readAttributeRemovedOnWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeRemovedOnWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeRemovedOnWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeDeviceDirectoryWithParams:(MTRReadParams * _Nullable)params completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeDeviceDirectoryWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeDeviceDirectoryWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeLocationDirectoryWithParams:(MTRReadParams * _Nullable)params completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeLocationDirectoryWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeLocationDirectoryWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface MTRBaseClusterEcosystemInformation (Availability) + +/** + * For all instance methods (reads, writes, commands) that take a completion, + * the completion will be called on the provided queue. + */ +- (instancetype _Nullable)initWithDevice:(MTRBaseDevice *)device + endpointID:(NSNumber *)endpointID + queue:(dispatch_queue_t)queue MTR_PROVISIONALLY_AVAILABLE; + +@end + /** * Cluster Commissioner Control * @@ -20912,6 +20991,104 @@ typedef NS_ENUM(uint8_t, MTRContentAppObserverStatus) { MTRContentAppObserverStatusUnexpectedData MTR_PROVISIONALLY_AVAILABLE = 0x01, } MTR_PROVISIONALLY_AVAILABLE; +typedef NS_ENUM(uint8_t, MTREcosystemInformationAreaTypeTag) { + MTREcosystemInformationAreaTypeTagAisle MTR_PROVISIONALLY_AVAILABLE = 0x00, + MTREcosystemInformationAreaTypeTagAttic MTR_PROVISIONALLY_AVAILABLE = 0x01, + MTREcosystemInformationAreaTypeTagBackDoor MTR_PROVISIONALLY_AVAILABLE = 0x02, + MTREcosystemInformationAreaTypeTagBackYard MTR_PROVISIONALLY_AVAILABLE = 0x03, + MTREcosystemInformationAreaTypeTagBalcony MTR_PROVISIONALLY_AVAILABLE = 0x04, + MTREcosystemInformationAreaTypeTagBallroom MTR_PROVISIONALLY_AVAILABLE = 0x05, + MTREcosystemInformationAreaTypeTagBathroom MTR_PROVISIONALLY_AVAILABLE = 0x06, + MTREcosystemInformationAreaTypeTagBedroom MTR_PROVISIONALLY_AVAILABLE = 0x07, + MTREcosystemInformationAreaTypeTagBorder MTR_PROVISIONALLY_AVAILABLE = 0x08, + MTREcosystemInformationAreaTypeTagBoxroom MTR_PROVISIONALLY_AVAILABLE = 0x09, + MTREcosystemInformationAreaTypeTagBreakfastRoom MTR_PROVISIONALLY_AVAILABLE = 0x0A, + MTREcosystemInformationAreaTypeTagCarport MTR_PROVISIONALLY_AVAILABLE = 0x0B, + MTREcosystemInformationAreaTypeTagCellar MTR_PROVISIONALLY_AVAILABLE = 0x0C, + MTREcosystemInformationAreaTypeTagCloakroom MTR_PROVISIONALLY_AVAILABLE = 0x0D, + MTREcosystemInformationAreaTypeTagCloset MTR_PROVISIONALLY_AVAILABLE = 0x0E, + MTREcosystemInformationAreaTypeTagConservatory MTR_PROVISIONALLY_AVAILABLE = 0x0F, + MTREcosystemInformationAreaTypeTagCorridor MTR_PROVISIONALLY_AVAILABLE = 0x10, + MTREcosystemInformationAreaTypeTagCraftRoom MTR_PROVISIONALLY_AVAILABLE = 0x11, + MTREcosystemInformationAreaTypeTagCupboard MTR_PROVISIONALLY_AVAILABLE = 0x12, + MTREcosystemInformationAreaTypeTagDeck MTR_PROVISIONALLY_AVAILABLE = 0x13, + MTREcosystemInformationAreaTypeTagDen MTR_PROVISIONALLY_AVAILABLE = 0x14, + MTREcosystemInformationAreaTypeTagDining MTR_PROVISIONALLY_AVAILABLE = 0x15, + MTREcosystemInformationAreaTypeTagDrawingRoom MTR_PROVISIONALLY_AVAILABLE = 0x16, + MTREcosystemInformationAreaTypeTagDressingRoom MTR_PROVISIONALLY_AVAILABLE = 0x17, + MTREcosystemInformationAreaTypeTagDriveway MTR_PROVISIONALLY_AVAILABLE = 0x18, + MTREcosystemInformationAreaTypeTagElevator MTR_PROVISIONALLY_AVAILABLE = 0x19, + MTREcosystemInformationAreaTypeTagEnsuite MTR_PROVISIONALLY_AVAILABLE = 0x1A, + MTREcosystemInformationAreaTypeTagEntrance MTR_PROVISIONALLY_AVAILABLE = 0x1B, + MTREcosystemInformationAreaTypeTagEntryway MTR_PROVISIONALLY_AVAILABLE = 0x1C, + MTREcosystemInformationAreaTypeTagFamilyRoom MTR_PROVISIONALLY_AVAILABLE = 0x1D, + MTREcosystemInformationAreaTypeTagFoyer MTR_PROVISIONALLY_AVAILABLE = 0x1E, + MTREcosystemInformationAreaTypeTagFrontDoor MTR_PROVISIONALLY_AVAILABLE = 0x1F, + MTREcosystemInformationAreaTypeTagFrontYard MTR_PROVISIONALLY_AVAILABLE = 0x20, + MTREcosystemInformationAreaTypeTagGameRoom MTR_PROVISIONALLY_AVAILABLE = 0x21, + MTREcosystemInformationAreaTypeTagGarage MTR_PROVISIONALLY_AVAILABLE = 0x22, + MTREcosystemInformationAreaTypeTagGarageDoor MTR_PROVISIONALLY_AVAILABLE = 0x23, + MTREcosystemInformationAreaTypeTagGarden MTR_PROVISIONALLY_AVAILABLE = 0x24, + MTREcosystemInformationAreaTypeTagGardenDoor MTR_PROVISIONALLY_AVAILABLE = 0x25, + MTREcosystemInformationAreaTypeTagGuestBathroom MTR_PROVISIONALLY_AVAILABLE = 0x26, + MTREcosystemInformationAreaTypeTagGuestBedroom MTR_PROVISIONALLY_AVAILABLE = 0x27, + MTREcosystemInformationAreaTypeTagGuestRestroom MTR_PROVISIONALLY_AVAILABLE = 0x28, + MTREcosystemInformationAreaTypeTagGuestRoom MTR_PROVISIONALLY_AVAILABLE = 0x29, + MTREcosystemInformationAreaTypeTagGym MTR_PROVISIONALLY_AVAILABLE = 0x2A, + MTREcosystemInformationAreaTypeTagHallway MTR_PROVISIONALLY_AVAILABLE = 0x2B, + MTREcosystemInformationAreaTypeTagHearthRoom MTR_PROVISIONALLY_AVAILABLE = 0x2C, + MTREcosystemInformationAreaTypeTagKidsRoom MTR_PROVISIONALLY_AVAILABLE = 0x2D, + MTREcosystemInformationAreaTypeTagKidsBedroom MTR_PROVISIONALLY_AVAILABLE = 0x2E, + MTREcosystemInformationAreaTypeTagKitchen MTR_PROVISIONALLY_AVAILABLE = 0x2F, + MTREcosystemInformationAreaTypeTagLarder MTR_PROVISIONALLY_AVAILABLE = 0x30, + MTREcosystemInformationAreaTypeTagLaundryRoom MTR_PROVISIONALLY_AVAILABLE = 0x31, + MTREcosystemInformationAreaTypeTagLawn MTR_PROVISIONALLY_AVAILABLE = 0x32, + MTREcosystemInformationAreaTypeTagLibrary MTR_PROVISIONALLY_AVAILABLE = 0x33, + MTREcosystemInformationAreaTypeTagLivingRoom MTR_PROVISIONALLY_AVAILABLE = 0x34, + MTREcosystemInformationAreaTypeTagLounge MTR_PROVISIONALLY_AVAILABLE = 0x35, + MTREcosystemInformationAreaTypeTagMediaTVRoom MTR_PROVISIONALLY_AVAILABLE = 0x36, + MTREcosystemInformationAreaTypeTagMudRoom MTR_PROVISIONALLY_AVAILABLE = 0x37, + MTREcosystemInformationAreaTypeTagMusicRoom MTR_PROVISIONALLY_AVAILABLE = 0x38, + MTREcosystemInformationAreaTypeTagNursery MTR_PROVISIONALLY_AVAILABLE = 0x39, + MTREcosystemInformationAreaTypeTagOffice MTR_PROVISIONALLY_AVAILABLE = 0x3A, + MTREcosystemInformationAreaTypeTagOutdoorKitchen MTR_PROVISIONALLY_AVAILABLE = 0x3B, + MTREcosystemInformationAreaTypeTagOutside MTR_PROVISIONALLY_AVAILABLE = 0x3C, + MTREcosystemInformationAreaTypeTagPantry MTR_PROVISIONALLY_AVAILABLE = 0x3D, + MTREcosystemInformationAreaTypeTagParkingLot MTR_PROVISIONALLY_AVAILABLE = 0x3E, + MTREcosystemInformationAreaTypeTagParlor MTR_PROVISIONALLY_AVAILABLE = 0x3F, + MTREcosystemInformationAreaTypeTagPatio MTR_PROVISIONALLY_AVAILABLE = 0x40, + MTREcosystemInformationAreaTypeTagPlayRoom MTR_PROVISIONALLY_AVAILABLE = 0x41, + MTREcosystemInformationAreaTypeTagPoolRoom MTR_PROVISIONALLY_AVAILABLE = 0x42, + MTREcosystemInformationAreaTypeTagPorch MTR_PROVISIONALLY_AVAILABLE = 0x43, + MTREcosystemInformationAreaTypeTagPrimaryBathroom MTR_PROVISIONALLY_AVAILABLE = 0x44, + MTREcosystemInformationAreaTypeTagPrimaryBedroom MTR_PROVISIONALLY_AVAILABLE = 0x45, + MTREcosystemInformationAreaTypeTagRamp MTR_PROVISIONALLY_AVAILABLE = 0x46, + MTREcosystemInformationAreaTypeTagReceptionRoom MTR_PROVISIONALLY_AVAILABLE = 0x47, + MTREcosystemInformationAreaTypeTagRecreationRoom MTR_PROVISIONALLY_AVAILABLE = 0x48, + MTREcosystemInformationAreaTypeTagRestroom MTR_PROVISIONALLY_AVAILABLE = 0x49, + MTREcosystemInformationAreaTypeTagRoof MTR_PROVISIONALLY_AVAILABLE = 0x4A, + MTREcosystemInformationAreaTypeTagSauna MTR_PROVISIONALLY_AVAILABLE = 0x4B, + MTREcosystemInformationAreaTypeTagScullery MTR_PROVISIONALLY_AVAILABLE = 0x4C, + MTREcosystemInformationAreaTypeTagSewingRoom MTR_PROVISIONALLY_AVAILABLE = 0x4D, + MTREcosystemInformationAreaTypeTagShed MTR_PROVISIONALLY_AVAILABLE = 0x4E, + MTREcosystemInformationAreaTypeTagSideDoor MTR_PROVISIONALLY_AVAILABLE = 0x4F, + MTREcosystemInformationAreaTypeTagSideYard MTR_PROVISIONALLY_AVAILABLE = 0x50, + MTREcosystemInformationAreaTypeTagSittingRoom MTR_PROVISIONALLY_AVAILABLE = 0x51, + MTREcosystemInformationAreaTypeTagSnug MTR_PROVISIONALLY_AVAILABLE = 0x52, + MTREcosystemInformationAreaTypeTagSpa MTR_PROVISIONALLY_AVAILABLE = 0x53, + MTREcosystemInformationAreaTypeTagStaircase MTR_PROVISIONALLY_AVAILABLE = 0x54, + MTREcosystemInformationAreaTypeTagSteamRoom MTR_PROVISIONALLY_AVAILABLE = 0x55, + MTREcosystemInformationAreaTypeTagStorageRoom MTR_PROVISIONALLY_AVAILABLE = 0x56, + MTREcosystemInformationAreaTypeTagStudio MTR_PROVISIONALLY_AVAILABLE = 0x57, + MTREcosystemInformationAreaTypeTagStudy MTR_PROVISIONALLY_AVAILABLE = 0x58, + MTREcosystemInformationAreaTypeTagSunRoom MTR_PROVISIONALLY_AVAILABLE = 0x59, + MTREcosystemInformationAreaTypeTagSwimmingPool MTR_PROVISIONALLY_AVAILABLE = 0x5A, + MTREcosystemInformationAreaTypeTagTerrace MTR_PROVISIONALLY_AVAILABLE = 0x5B, + MTREcosystemInformationAreaTypeTagUtilityRoom MTR_PROVISIONALLY_AVAILABLE = 0x5C, + MTREcosystemInformationAreaTypeTagWard MTR_PROVISIONALLY_AVAILABLE = 0x5D, + MTREcosystemInformationAreaTypeTagWorkshop MTR_PROVISIONALLY_AVAILABLE = 0x5E, +} MTR_PROVISIONALLY_AVAILABLE; + typedef NS_OPTIONS(uint32_t, MTRCommissionerControlSupportedDeviceCategoryBitmap) { MTRCommissionerControlSupportedDeviceCategoryBitmapFabricSynchronization MTR_PROVISIONALLY_AVAILABLE = 0x1, } MTR_PROVISIONALLY_AVAILABLE; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index ddb25fb19bd0a8..641fea65515da4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -105123,6 +105123,334 @@ + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheC @end +@implementation MTRBaseClusterEcosystemInformation + +- (void)readAttributeRemovedOnWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::RemovedOn::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeRemovedOnWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::RemovedOn::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeRemovedOnWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::RemovedOn::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeDeviceDirectoryWithParams:(MTRReadParams * _Nullable)params completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::DeviceDirectory::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeDeviceDirectoryWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::DeviceDirectory::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeDeviceDirectoryWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::DeviceDirectory::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeLocationDirectoryWithParams:(MTRReadParams * _Nullable)params completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::LocationDirectory::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeLocationDirectoryWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::LocationDirectory::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeLocationDirectoryWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::LocationDirectory::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::GeneratedCommandList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::GeneratedCommandList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::GeneratedCommandList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::AcceptedCommandList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::AcceptedCommandList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::AcceptedCommandList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::EventList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::EventList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::EventList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::AttributeList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::AttributeList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::AttributeList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::FeatureMap::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::FeatureMap::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::FeatureMap::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::ClusterRevision::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = EcosystemInformation::Attributes::ClusterRevision::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = EcosystemInformation::Attributes::ClusterRevision::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +@end + @implementation MTRBaseClusterCommissionerControl - (void)requestCommissioningApprovalWithParams:(MTRCommissionerControlClusterRequestCommissioningApprovalParams *)params completion:(MTRStatusCompletion)completion diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index ff6351d9a50ff3..2178edd403cfe4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -204,6 +204,7 @@ typedef NS_ENUM(uint32_t, MTRClusterIDType) { MTRClusterIDTypeAccountLoginID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000050E, MTRClusterIDTypeContentControlID MTR_PROVISIONALLY_AVAILABLE = 0x0000050F, MTRClusterIDTypeContentAppObserverID MTR_PROVISIONALLY_AVAILABLE = 0x00000510, + MTRClusterIDTypeEcosystemInformationID MTR_PROVISIONALLY_AVAILABLE = 0x00000750, MTRClusterIDTypeCommissionerControlID MTR_PROVISIONALLY_AVAILABLE = 0x00000751, MTRClusterIDTypeElectricalMeasurementID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000B04, MTRClusterIDTypeUnitTestingID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0xFFF1FC05, @@ -4888,6 +4889,17 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterContentAppObserverAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, MTRAttributeIDTypeClusterContentAppObserverAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster EcosystemInformation attributes + MTRAttributeIDTypeClusterEcosystemInformationAttributeRemovedOnID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRAttributeIDTypeClusterEcosystemInformationAttributeDeviceDirectoryID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + MTRAttributeIDTypeClusterEcosystemInformationAttributeLocationDirectoryID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, + MTRAttributeIDTypeClusterEcosystemInformationAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, + MTRAttributeIDTypeClusterEcosystemInformationAttributeAcceptedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, + MTRAttributeIDTypeClusterEcosystemInformationAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, + MTRAttributeIDTypeClusterEcosystemInformationAttributeAttributeListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAttributeListID, + MTRAttributeIDTypeClusterEcosystemInformationAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, + MTRAttributeIDTypeClusterEcosystemInformationAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster CommissionerControl attributes MTRAttributeIDTypeClusterCommissionerControlAttributeSupportedDeviceCategoriesID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, MTRAttributeIDTypeClusterCommissionerControlAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm index 91bdbf48d13e74..575661bfa078bd 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm @@ -378,6 +378,9 @@ case MTRClusterIDTypeContentAppObserverID: result = @"ContentAppObserver"; break; + case MTRClusterIDTypeEcosystemInformationID: + result = @"EcosystemInformation"; + break; case MTRClusterIDTypeCommissionerControlID: result = @"CommissionerControl"; break; @@ -8189,6 +8192,52 @@ break; } + case MTRClusterIDTypeEcosystemInformationID: + + switch (attributeID) { + + // Cluster EcosystemInformation attributes + case MTRAttributeIDTypeClusterEcosystemInformationAttributeRemovedOnID: + result = @"RemovedOn"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeDeviceDirectoryID: + result = @"DeviceDirectory"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeLocationDirectoryID: + result = @"LocationDirectory"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeGeneratedCommandListID: + result = @"GeneratedCommandList"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeAcceptedCommandListID: + result = @"AcceptedCommandList"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeEventListID: + result = @"EventList"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeAttributeListID: + result = @"AttributeList"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeFeatureMapID: + result = @"FeatureMap"; + break; + + case MTRAttributeIDTypeClusterEcosystemInformationAttributeClusterRevisionID: + result = @"ClusterRevision"; + break; + + default: + result = [NSString stringWithFormat:@"", attributeID]; + break; + } + case MTRClusterIDTypeCommissionerControlID: switch (attributeID) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index a30b71bc75cb22..cefb92935beab4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -6999,6 +6999,48 @@ MTR_PROVISIONALLY_AVAILABLE @end +/** + * Cluster Ecosystem Information + * Provides extended device information for all the logical devices represented by a Bridged Node. + */ +MTR_PROVISIONALLY_AVAILABLE +@interface MTRClusterEcosystemInformation : MTRGenericCluster + +- (NSDictionary * _Nullable)readAttributeRemovedOnWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeDeviceDirectoryWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeLocationDirectoryWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface MTRClusterEcosystemInformation (Availability) + +/** + * The queue is currently unused, but may be used in the future for calling completions + * for command invocations if commands are added to this cluster. + */ +- (instancetype _Nullable)initWithDevice:(MTRDevice *)device + endpointID:(NSNumber *)endpointID + queue:(dispatch_queue_t)queue MTR_PROVISIONALLY_AVAILABLE; + +@end + /** * Cluster Commissioner Control * Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index bab799b843c24f..8c38a6c584b79e 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -20009,6 +20009,55 @@ - (void)contentAppMessageWithParams:(MTRContentAppObserverClusterContentAppMessa @end +@implementation MTRClusterEcosystemInformation + +- (NSDictionary * _Nullable)readAttributeRemovedOnWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeRemovedOnID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeDeviceDirectoryWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeDeviceDirectoryID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeLocationDirectoryWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeLocationDirectoryID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeGeneratedCommandListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeAcceptedCommandListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeEventListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeAttributeListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeFeatureMapID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeEcosystemInformationID) attributeID:@(MTRAttributeIDTypeClusterEcosystemInformationAttributeClusterRevisionID) params:params]; +} + +@end + @implementation MTRClusterCommissionerControl - (void)requestCommissioningApprovalWithParams:(MTRCommissionerControlClusterRequestCommissioningApprovalParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm index 4abe6bf88050bd..6fdc015ad0aac3 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm @@ -1154,6 +1154,15 @@ static BOOL CommandNeedsTimedInvokeInContentAppObserverCluster(AttributeId aAttr } } } +static BOOL CommandNeedsTimedInvokeInEcosystemInformationCluster(AttributeId aAttributeId) +{ + using namespace Clusters::EcosystemInformation; + switch (aAttributeId) { + default: { + return NO; + } + } +} static BOOL CommandNeedsTimedInvokeInCommissionerControlCluster(AttributeId aAttributeId) { using namespace Clusters::CommissionerControl; @@ -1551,6 +1560,9 @@ BOOL MTRCommandNeedsTimedInvoke(NSNumber * _Nonnull aClusterID, NSNumber * _Nonn case Clusters::ContentAppObserver::Id: { return CommandNeedsTimedInvokeInContentAppObserverCluster(commandID); } + case Clusters::EcosystemInformation::Id: { + return CommandNeedsTimedInvokeInEcosystemInformationCluster(commandID); + } case Clusters::CommissionerControl::Id: { return CommandNeedsTimedInvokeInCommissionerControlCluster(commandID); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm index 13f125b6328642..fd2bee34f1aafa 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm @@ -4458,6 +4458,18 @@ static id _Nullable DecodeEventPayloadForContentAppObserverCluster(EventId aEven *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; return nil; } +static id _Nullable DecodeEventPayloadForEcosystemInformationCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +{ + using namespace Clusters::EcosystemInformation; + switch (aEventId) { + default: { + break; + } + } + + *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; + return nil; +} static id _Nullable DecodeEventPayloadForCommissionerControlCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { using namespace Clusters::CommissionerControl; @@ -5047,6 +5059,9 @@ id _Nullable MTRDecodeEventPayload(const ConcreteEventPath & aPath, TLV::TLVRead case Clusters::ContentAppObserver::Id: { return DecodeEventPayloadForContentAppObserverCluster(aPath.mEventId, aReader, aError); } + case Clusters::EcosystemInformation::Id: { + return DecodeEventPayloadForEcosystemInformationCluster(aPath.mEventId, aReader, aError); + } case Clusters::CommissionerControl::Id: { return DecodeEventPayloadForCommissionerControlCluster(aPath.mEventId, aReader, aError); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index d4da2052d3cb3e..f87d5b31dd75b5 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -2047,6 +2047,39 @@ MTR_PROVISIONALLY_AVAILABLE @interface MTRContentControlClusterRemainingScreenTimeExpiredEvent : NSObject @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTREcosystemInformationClusterHomeLocationStruct : NSObject +@property (nonatomic, copy) NSString * _Nonnull locationName MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable floorNumber MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable areaType MTR_PROVISIONALLY_AVAILABLE; +@end + +MTR_PROVISIONALLY_AVAILABLE +@interface MTREcosystemInformationClusterEcosystemLocationStruct : NSObject +@property (nonatomic, copy) NSString * _Nonnull uniqueLocationID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) MTREcosystemInformationClusterHomeLocationStruct * _Nonnull locationDescriptor MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull locationDescriptorLastEdit MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull fabricIndex MTR_PROVISIONALLY_AVAILABLE; +@end + +MTR_PROVISIONALLY_AVAILABLE +@interface MTREcosystemInformationClusterDeviceTypeStruct : NSObject +@property (nonatomic, copy) NSNumber * _Nonnull deviceType MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull revision MTR_PROVISIONALLY_AVAILABLE; +@end + +MTR_PROVISIONALLY_AVAILABLE +@interface MTREcosystemInformationClusterEcosystemDeviceStruct : NSObject +@property (nonatomic, copy) NSString * _Nullable deviceName MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable deviceNameLastEdit MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull bridgedEndpoint MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull originalEndpoint MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSArray * _Nonnull deviceTypes MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSArray * _Nonnull uniqueLocationIDs MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull uniqueLocationIDsLastEdit MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull fabricIndex MTR_PROVISIONALLY_AVAILABLE; +@end + MTR_PROVISIONALLY_AVAILABLE @interface MTRCommissionerControlClusterCommissioningRequestResultEvent : NSObject @property (nonatomic, copy) NSNumber * _Nonnull requestId MTR_PROVISIONALLY_AVAILABLE; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index 99503c79d6e2bf..dc7a0ad672bb25 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -8427,6 +8427,153 @@ - (NSString *)description @end +@implementation MTREcosystemInformationClusterHomeLocationStruct +- (instancetype)init +{ + if (self = [super init]) { + + _locationName = @""; + + _floorNumber = nil; + + _areaType = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTREcosystemInformationClusterHomeLocationStruct alloc] init]; + + other.locationName = self.locationName; + other.floorNumber = self.floorNumber; + other.areaType = self.areaType; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: locationName:%@; floorNumber:%@; areaType:%@; >", NSStringFromClass([self class]), _locationName, _floorNumber, _areaType]; + return descriptionString; +} + +@end + +@implementation MTREcosystemInformationClusterEcosystemLocationStruct +- (instancetype)init +{ + if (self = [super init]) { + + _uniqueLocationID = @""; + + _locationDescriptor = [MTREcosystemInformationClusterHomeLocationStruct new]; + + _locationDescriptorLastEdit = @(0); + + _fabricIndex = @(0); + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTREcosystemInformationClusterEcosystemLocationStruct alloc] init]; + + other.uniqueLocationID = self.uniqueLocationID; + other.locationDescriptor = self.locationDescriptor; + other.locationDescriptorLastEdit = self.locationDescriptorLastEdit; + other.fabricIndex = self.fabricIndex; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: uniqueLocationID:%@; locationDescriptor:%@; locationDescriptorLastEdit:%@; fabricIndex:%@; >", NSStringFromClass([self class]), _uniqueLocationID, _locationDescriptor, _locationDescriptorLastEdit, _fabricIndex]; + return descriptionString; +} + +@end + +@implementation MTREcosystemInformationClusterDeviceTypeStruct +- (instancetype)init +{ + if (self = [super init]) { + + _deviceType = @(0); + + _revision = @(0); + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTREcosystemInformationClusterDeviceTypeStruct alloc] init]; + + other.deviceType = self.deviceType; + other.revision = self.revision; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: deviceType:%@; revision:%@; >", NSStringFromClass([self class]), _deviceType, _revision]; + return descriptionString; +} + +@end + +@implementation MTREcosystemInformationClusterEcosystemDeviceStruct +- (instancetype)init +{ + if (self = [super init]) { + + _deviceName = nil; + + _deviceNameLastEdit = nil; + + _bridgedEndpoint = @(0); + + _originalEndpoint = @(0); + + _deviceTypes = [NSArray array]; + + _uniqueLocationIDs = [NSArray array]; + + _uniqueLocationIDsLastEdit = @(0); + + _fabricIndex = @(0); + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTREcosystemInformationClusterEcosystemDeviceStruct alloc] init]; + + other.deviceName = self.deviceName; + other.deviceNameLastEdit = self.deviceNameLastEdit; + other.bridgedEndpoint = self.bridgedEndpoint; + other.originalEndpoint = self.originalEndpoint; + other.deviceTypes = self.deviceTypes; + other.uniqueLocationIDs = self.uniqueLocationIDs; + other.uniqueLocationIDsLastEdit = self.uniqueLocationIDsLastEdit; + other.fabricIndex = self.fabricIndex; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: deviceName:%@; deviceNameLastEdit:%@; bridgedEndpoint:%@; originalEndpoint:%@; deviceTypes:%@; uniqueLocationIDs:%@; uniqueLocationIDsLastEdit:%@; fabricIndex:%@; >", NSStringFromClass([self class]), _deviceName, _deviceNameLastEdit, _bridgedEndpoint, _originalEndpoint, _deviceTypes, _uniqueLocationIDs, _uniqueLocationIDsLastEdit, _fabricIndex]; + return descriptionString; +} + +@end + @implementation MTRCommissionerControlClusterCommissioningRequestResultEvent - (instancetype)init { diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index ca35f4d8464e3c..4f4d62a3e67bd6 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -38783,6 +38783,195 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu } // namespace Attributes } // namespace ContentAppObserver +namespace EcosystemInformation { +namespace Attributes { + +namespace RemovedOn { + +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, DataModel::Nullable & value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (Traits::IsNullValue(temp)) + { + value.SetNull(); + } + else + { + value.SetNonNull() = Traits::StorageToWorking(temp); + } + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_EPOCH_US_ATTRIBUTE_TYPE, + markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_EPOCH_US_ATTRIBUTE_TYPE); +} + +Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType value; + Traits::SetNull(value); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_EPOCH_US_ATTRIBUTE_TYPE, + markDirty); +} + +Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType value; + Traits::SetNull(value); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_EPOCH_US_ATTRIBUTE_TYPE); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value, + MarkAttributeDirty markDirty) +{ + if (value.IsNull()) + { + return SetNull(endpoint, markDirty); + } + + return Set(endpoint, value.Value(), markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) +{ + if (value.IsNull()) + { + return SetNull(endpoint); + } + + return Set(endpoint, value.Value()); +} + +} // namespace RemovedOn + +namespace FeatureMap { + +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE, + markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); +} + +} // namespace FeatureMap + +namespace ClusterRevision { + +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE, markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::EcosystemInformation::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); +} + +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace EcosystemInformation + namespace CommissionerControl { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 78334996c0e75e..da42291b70eb2a 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -5984,6 +5984,35 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu } // namespace Attributes } // namespace ContentAppObserver +namespace EcosystemInformation { +namespace Attributes { + +namespace RemovedOn { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, DataModel::Nullable & value); // epoch_us +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value, MarkAttributeDirty markDirty); +Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint); +Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint, MarkAttributeDirty markDirty); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value, + MarkAttributeDirty markDirty); +} // namespace RemovedOn + +namespace FeatureMap { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value, MarkAttributeDirty markDirty); +} // namespace FeatureMap + +namespace ClusterRevision { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value); // int16u +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty); +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace EcosystemInformation + namespace CommissionerControl { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 03f0b7bbef238e..f1aa9705d7c8c3 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -633,6 +633,11 @@ void emberAfContentControlClusterInitCallback(chip::EndpointId endpoint); */ void emberAfContentAppObserverClusterInitCallback(chip::EndpointId endpoint); +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfEcosystemInformationClusterInitCallback(chip::EndpointId endpoint); + /** * @param endpoint Endpoint that is being initialized */ @@ -5298,6 +5303,44 @@ chip::Protocols::InteractionModel::Status MatterContentAppObserverClusterServerP */ void emberAfContentAppObserverClusterServerTickCallback(chip::EndpointId endpoint); +// +// Ecosystem Information Cluster +// + +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfEcosystemInformationClusterServerInitCallback(chip::EndpointId endpoint); + +/** + * @param endpoint Endpoint that is being shutdown + */ +void MatterEcosystemInformationClusterServerShutdownCallback(chip::EndpointId endpoint); + +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfEcosystemInformationClusterClientInitCallback(chip::EndpointId endpoint); + +/** + * @param attributePath Concrete attribute path that changed + */ +void MatterEcosystemInformationClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath); + +/** + * @param attributePath Concrete attribute path to be changed + * @param attributeType Attribute type + * @param size Attribute size + * @param value Attribute value + */ +chip::Protocols::InteractionModel::Status MatterEcosystemInformationClusterServerPreAttributeChangedCallback( + const chip::app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value); + +/** + * @param endpoint Endpoint that is being served + */ +void emberAfEcosystemInformationClusterServerTickCallback(chip::EndpointId endpoint); + // // Commissioner Control Cluster // diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index 0304b683406b8b..dd4bf2387c3a2e 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -24,6 +24,111 @@ namespace chip { namespace app { namespace Clusters { +static auto __attribute__((unused)) EnsureKnownEnumValue(detail::AreaTypeTag val) +{ + using EnumType = detail::AreaTypeTag; + switch (val) + { + case EnumType::kAisle: + case EnumType::kAttic: + case EnumType::kBackDoor: + case EnumType::kBackYard: + case EnumType::kBalcony: + case EnumType::kBallroom: + case EnumType::kBathroom: + case EnumType::kBedroom: + case EnumType::kBorder: + case EnumType::kBoxroom: + case EnumType::kBreakfastRoom: + case EnumType::kCarport: + case EnumType::kCellar: + case EnumType::kCloakroom: + case EnumType::kCloset: + case EnumType::kConservatory: + case EnumType::kCorridor: + case EnumType::kCraftRoom: + case EnumType::kCupboard: + case EnumType::kDeck: + case EnumType::kDen: + case EnumType::kDining: + case EnumType::kDrawingRoom: + case EnumType::kDressingRoom: + case EnumType::kDriveway: + case EnumType::kElevator: + case EnumType::kEnsuite: + case EnumType::kEntrance: + case EnumType::kEntryway: + case EnumType::kFamilyRoom: + case EnumType::kFoyer: + case EnumType::kFrontDoor: + case EnumType::kFrontYard: + case EnumType::kGameRoom: + case EnumType::kGarage: + case EnumType::kGarageDoor: + case EnumType::kGarden: + case EnumType::kGardenDoor: + case EnumType::kGuestBathroom: + case EnumType::kGuestBedroom: + case EnumType::kGuestRestroom: + case EnumType::kGuestRoom: + case EnumType::kGym: + case EnumType::kHallway: + case EnumType::kHearthRoom: + case EnumType::kKidsRoom: + case EnumType::kKidsBedroom: + case EnumType::kKitchen: + case EnumType::kLarder: + case EnumType::kLaundryRoom: + case EnumType::kLawn: + case EnumType::kLibrary: + case EnumType::kLivingRoom: + case EnumType::kLounge: + case EnumType::kMediaTvRoom: + case EnumType::kMudRoom: + case EnumType::kMusicRoom: + case EnumType::kNursery: + case EnumType::kOffice: + case EnumType::kOutdoorKitchen: + case EnumType::kOutside: + case EnumType::kPantry: + case EnumType::kParkingLot: + case EnumType::kParlor: + case EnumType::kPatio: + case EnumType::kPlayRoom: + case EnumType::kPoolRoom: + case EnumType::kPorch: + case EnumType::kPrimaryBathroom: + case EnumType::kPrimaryBedroom: + case EnumType::kRamp: + case EnumType::kReceptionRoom: + case EnumType::kRecreationRoom: + case EnumType::kRestroom: + case EnumType::kRoof: + case EnumType::kSauna: + case EnumType::kScullery: + case EnumType::kSewingRoom: + case EnumType::kShed: + case EnumType::kSideDoor: + case EnumType::kSideYard: + case EnumType::kSittingRoom: + case EnumType::kSnug: + case EnumType::kSpa: + case EnumType::kStaircase: + case EnumType::kSteamRoom: + case EnumType::kStorageRoom: + case EnumType::kStudio: + case EnumType::kStudy: + case EnumType::kSunRoom: + case EnumType::kSwimmingPool: + case EnumType::kTerrace: + case EnumType::kUtilityRoom: + case EnumType::kWard: + case EnumType::kWorkshop: + return val; + default: + return EnumType::kUnknownEnumValue; + } +} static auto __attribute__((unused)) EnsureKnownEnumValue(detail::ChangeIndicationEnum val) { using EnumType = detail::ChangeIndicationEnum; @@ -2294,111 +2399,6 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(WindowCovering::Type va } } -static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::AreaTypeTag val) -{ - using EnumType = ServiceArea::AreaTypeTag; - switch (val) - { - case EnumType::kAisle: - case EnumType::kAttic: - case EnumType::kBackDoor: - case EnumType::kBackYard: - case EnumType::kBalcony: - case EnumType::kBallroom: - case EnumType::kBathroom: - case EnumType::kBedroom: - case EnumType::kBorder: - case EnumType::kBoxroom: - case EnumType::kBreakfastRoom: - case EnumType::kCarport: - case EnumType::kCellar: - case EnumType::kCloakroom: - case EnumType::kCloset: - case EnumType::kConservatory: - case EnumType::kCorridor: - case EnumType::kCraftRoom: - case EnumType::kCupboard: - case EnumType::kDeck: - case EnumType::kDen: - case EnumType::kDining: - case EnumType::kDrawingRoom: - case EnumType::kDressingRoom: - case EnumType::kDriveway: - case EnumType::kElevator: - case EnumType::kEnsuite: - case EnumType::kEntrance: - case EnumType::kEntryway: - case EnumType::kFamilyRoom: - case EnumType::kFoyer: - case EnumType::kFrontDoor: - case EnumType::kFrontYard: - case EnumType::kGameRoom: - case EnumType::kGarage: - case EnumType::kGarageDoor: - case EnumType::kGarden: - case EnumType::kGardenDoor: - case EnumType::kGuestBathroom: - case EnumType::kGuestBedroom: - case EnumType::kGuestRestroom: - case EnumType::kGuestRoom: - case EnumType::kGym: - case EnumType::kHallway: - case EnumType::kHearthRoom: - case EnumType::kKidsRoom: - case EnumType::kKidsBedroom: - case EnumType::kKitchen: - case EnumType::kLarder: - case EnumType::kLaundryRoom: - case EnumType::kLawn: - case EnumType::kLibrary: - case EnumType::kLivingRoom: - case EnumType::kLounge: - case EnumType::kMediaTvRoom: - case EnumType::kMudRoom: - case EnumType::kMusicRoom: - case EnumType::kNursery: - case EnumType::kOffice: - case EnumType::kOutdoorKitchen: - case EnumType::kOutside: - case EnumType::kPantry: - case EnumType::kParkingLot: - case EnumType::kParlor: - case EnumType::kPatio: - case EnumType::kPlayRoom: - case EnumType::kPoolRoom: - case EnumType::kPorch: - case EnumType::kPrimaryBathroom: - case EnumType::kPrimaryBedroom: - case EnumType::kRamp: - case EnumType::kReceptionRoom: - case EnumType::kRecreationRoom: - case EnumType::kRestroom: - case EnumType::kRoof: - case EnumType::kSauna: - case EnumType::kScullery: - case EnumType::kSewingRoom: - case EnumType::kShed: - case EnumType::kSideDoor: - case EnumType::kSideYard: - case EnumType::kSittingRoom: - case EnumType::kSnug: - case EnumType::kSpa: - case EnumType::kStaircase: - case EnumType::kSteamRoom: - case EnumType::kStorageRoom: - case EnumType::kStudio: - case EnumType::kStudy: - case EnumType::kSunRoom: - case EnumType::kSwimmingPool: - case EnumType::kTerrace: - case EnumType::kUtilityRoom: - case EnumType::kWard: - case EnumType::kWorkshop: - return val; - default: - return EnumType::kUnknownEnumValue; - } -} static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::FloorSurfaceTag val) { using EnumType = ServiceArea::FloorSurfaceTag; diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index 612637d3af1776..aaa24825e49d82 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -28,6 +28,111 @@ namespace Clusters { namespace detail { // Enums shared across multiple clusters. +// Enum for AreaTypeTag +enum class AreaTypeTag : uint8_t +{ + kAisle = 0x00, + kAttic = 0x01, + kBackDoor = 0x02, + kBackYard = 0x03, + kBalcony = 0x04, + kBallroom = 0x05, + kBathroom = 0x06, + kBedroom = 0x07, + kBorder = 0x08, + kBoxroom = 0x09, + kBreakfastRoom = 0x0A, + kCarport = 0x0B, + kCellar = 0x0C, + kCloakroom = 0x0D, + kCloset = 0x0E, + kConservatory = 0x0F, + kCorridor = 0x10, + kCraftRoom = 0x11, + kCupboard = 0x12, + kDeck = 0x13, + kDen = 0x14, + kDining = 0x15, + kDrawingRoom = 0x16, + kDressingRoom = 0x17, + kDriveway = 0x18, + kElevator = 0x19, + kEnsuite = 0x1A, + kEntrance = 0x1B, + kEntryway = 0x1C, + kFamilyRoom = 0x1D, + kFoyer = 0x1E, + kFrontDoor = 0x1F, + kFrontYard = 0x20, + kGameRoom = 0x21, + kGarage = 0x22, + kGarageDoor = 0x23, + kGarden = 0x24, + kGardenDoor = 0x25, + kGuestBathroom = 0x26, + kGuestBedroom = 0x27, + kGuestRestroom = 0x28, + kGuestRoom = 0x29, + kGym = 0x2A, + kHallway = 0x2B, + kHearthRoom = 0x2C, + kKidsRoom = 0x2D, + kKidsBedroom = 0x2E, + kKitchen = 0x2F, + kLarder = 0x30, + kLaundryRoom = 0x31, + kLawn = 0x32, + kLibrary = 0x33, + kLivingRoom = 0x34, + kLounge = 0x35, + kMediaTvRoom = 0x36, + kMudRoom = 0x37, + kMusicRoom = 0x38, + kNursery = 0x39, + kOffice = 0x3A, + kOutdoorKitchen = 0x3B, + kOutside = 0x3C, + kPantry = 0x3D, + kParkingLot = 0x3E, + kParlor = 0x3F, + kPatio = 0x40, + kPlayRoom = 0x41, + kPoolRoom = 0x42, + kPorch = 0x43, + kPrimaryBathroom = 0x44, + kPrimaryBedroom = 0x45, + kRamp = 0x46, + kReceptionRoom = 0x47, + kRecreationRoom = 0x48, + kRestroom = 0x49, + kRoof = 0x4A, + kSauna = 0x4B, + kScullery = 0x4C, + kSewingRoom = 0x4D, + kShed = 0x4E, + kSideDoor = 0x4F, + kSideYard = 0x50, + kSittingRoom = 0x51, + kSnug = 0x52, + kSpa = 0x53, + kStaircase = 0x54, + kSteamRoom = 0x55, + kStorageRoom = 0x56, + kStudio = 0x57, + kStudy = 0x58, + kSunRoom = 0x59, + kSwimmingPool = 0x5A, + kTerrace = 0x5B, + kUtilityRoom = 0x5C, + kWard = 0x5D, + kWorkshop = 0x5E, + // All received enum values that are not listed above will be mapped + // to kUnknownEnumValue. This is a helper enum value that should only + // be used by code to process how it handles receiving and unknown + // enum value. This specific should never be transmitted. + kUnknownEnumValue = 95, +}; + // Enum for ChangeIndicationEnum enum class ChangeIndicationEnum : uint8_t { @@ -3512,110 +3617,7 @@ enum class BarrierControlSafetyStatus : uint16_t namespace ServiceArea { -// Enum for AreaTypeTag -enum class AreaTypeTag : uint8_t -{ - kAisle = 0x00, - kAttic = 0x01, - kBackDoor = 0x02, - kBackYard = 0x03, - kBalcony = 0x04, - kBallroom = 0x05, - kBathroom = 0x06, - kBedroom = 0x07, - kBorder = 0x08, - kBoxroom = 0x09, - kBreakfastRoom = 0x0A, - kCarport = 0x0B, - kCellar = 0x0C, - kCloakroom = 0x0D, - kCloset = 0x0E, - kConservatory = 0x0F, - kCorridor = 0x10, - kCraftRoom = 0x11, - kCupboard = 0x12, - kDeck = 0x13, - kDen = 0x14, - kDining = 0x15, - kDrawingRoom = 0x16, - kDressingRoom = 0x17, - kDriveway = 0x18, - kElevator = 0x19, - kEnsuite = 0x1A, - kEntrance = 0x1B, - kEntryway = 0x1C, - kFamilyRoom = 0x1D, - kFoyer = 0x1E, - kFrontDoor = 0x1F, - kFrontYard = 0x20, - kGameRoom = 0x21, - kGarage = 0x22, - kGarageDoor = 0x23, - kGarden = 0x24, - kGardenDoor = 0x25, - kGuestBathroom = 0x26, - kGuestBedroom = 0x27, - kGuestRestroom = 0x28, - kGuestRoom = 0x29, - kGym = 0x2A, - kHallway = 0x2B, - kHearthRoom = 0x2C, - kKidsRoom = 0x2D, - kKidsBedroom = 0x2E, - kKitchen = 0x2F, - kLarder = 0x30, - kLaundryRoom = 0x31, - kLawn = 0x32, - kLibrary = 0x33, - kLivingRoom = 0x34, - kLounge = 0x35, - kMediaTvRoom = 0x36, - kMudRoom = 0x37, - kMusicRoom = 0x38, - kNursery = 0x39, - kOffice = 0x3A, - kOutdoorKitchen = 0x3B, - kOutside = 0x3C, - kPantry = 0x3D, - kParkingLot = 0x3E, - kParlor = 0x3F, - kPatio = 0x40, - kPlayRoom = 0x41, - kPoolRoom = 0x42, - kPorch = 0x43, - kPrimaryBathroom = 0x44, - kPrimaryBedroom = 0x45, - kRamp = 0x46, - kReceptionRoom = 0x47, - kRecreationRoom = 0x48, - kRestroom = 0x49, - kRoof = 0x4A, - kSauna = 0x4B, - kScullery = 0x4C, - kSewingRoom = 0x4D, - kShed = 0x4E, - kSideDoor = 0x4F, - kSideYard = 0x50, - kSittingRoom = 0x51, - kSnug = 0x52, - kSpa = 0x53, - kStaircase = 0x54, - kSteamRoom = 0x55, - kStorageRoom = 0x56, - kStudio = 0x57, - kStudy = 0x58, - kSunRoom = 0x59, - kSwimmingPool = 0x5A, - kTerrace = 0x5B, - kUtilityRoom = 0x5C, - kWard = 0x5D, - kWorkshop = 0x5E, - // All received enum values that are not listed above will be mapped - // to kUnknownEnumValue. This is a helper enum value that should only - // be used by code to process how it handles receiving and unknown - // enum value. This specific should never be transmitted. - kUnknownEnumValue = 95, -}; +using AreaTypeTag = Clusters::detail::AreaTypeTag; // Enum for FloorSurfaceTag enum class FloorSurfaceTag : uint8_t @@ -5204,6 +5206,11 @@ enum class StatusEnum : uint8_t }; } // namespace ContentAppObserver +namespace EcosystemInformation { + +using AreaTypeTag = Clusters::detail::AreaTypeTag; +} // namespace EcosystemInformation + namespace CommissionerControl { // Bitmap for SupportedDeviceCategoryBitmap diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 7a08cb455c6452..9126422f85bd03 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -294,6 +294,93 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } // namespace MeasurementAccuracyStruct +namespace HomeLocationStruct { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kLocationName), locationName); + encoder.Encode(to_underlying(Fields::kFloorNumber), floorNumber); + encoder.Encode(to_underlying(Fields::kAreaType), areaType); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kLocationName)) + { + err = DataModel::Decode(reader, locationName); + } + else if (__context_tag == to_underlying(Fields::kFloorNumber)) + { + err = DataModel::Decode(reader, floorNumber); + } + else if (__context_tag == to_underlying(Fields::kAreaType)) + { + err = DataModel::Decode(reader, areaType); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} + +} // namespace HomeLocationStruct + +namespace DeviceTypeStruct { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kDeviceType), deviceType); + encoder.Encode(to_underlying(Fields::kRevision), revision); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kDeviceType)) + { + err = DataModel::Decode(reader, deviceType); + } + else if (__context_tag == to_underlying(Fields::kRevision)) + { + err = DataModel::Decode(reader, revision); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} + +} // namespace DeviceTypeStruct + namespace ApplicationStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { @@ -1761,47 +1848,6 @@ namespace Events {} // namespace Events namespace Descriptor { namespace Structs { -namespace DeviceTypeStruct { -CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const -{ - DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - encoder.Encode(to_underlying(Fields::kDeviceType), deviceType); - encoder.Encode(to_underlying(Fields::kRevision), revision); - return encoder.Finalize(); -} - -CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) -{ - detail::StructDecodeIterator __iterator(reader); - while (true) - { - auto __element = __iterator.Next(); - if (std::holds_alternative(__element)) - { - return std::get(__element); - } - - CHIP_ERROR err = CHIP_NO_ERROR; - const uint8_t __context_tag = std::get(__element); - - if (__context_tag == to_underlying(Fields::kDeviceType)) - { - err = DataModel::Decode(reader, deviceType); - } - else if (__context_tag == to_underlying(Fields::kRevision)) - { - err = DataModel::Decode(reader, revision); - } - else - { - } - - ReturnErrorOnFailure(err); - } -} - -} // namespace DeviceTypeStruct - namespace SemanticTagStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { @@ -19798,52 +19844,6 @@ namespace Events {} // namespace Events namespace ServiceArea { namespace Structs { -namespace HomeLocationStruct { -CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const -{ - DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - encoder.Encode(to_underlying(Fields::kLocationName), locationName); - encoder.Encode(to_underlying(Fields::kFloorNumber), floorNumber); - encoder.Encode(to_underlying(Fields::kAreaType), areaType); - return encoder.Finalize(); -} - -CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) -{ - detail::StructDecodeIterator __iterator(reader); - while (true) - { - auto __element = __iterator.Next(); - if (std::holds_alternative(__element)) - { - return std::get(__element); - } - - CHIP_ERROR err = CHIP_NO_ERROR; - const uint8_t __context_tag = std::get(__element); - - if (__context_tag == to_underlying(Fields::kLocationName)) - { - err = DataModel::Decode(reader, locationName); - } - else if (__context_tag == to_underlying(Fields::kFloorNumber)) - { - err = DataModel::Decode(reader, floorNumber); - } - else if (__context_tag == to_underlying(Fields::kAreaType)) - { - err = DataModel::Decode(reader, areaType); - } - else - { - } - - ReturnErrorOnFailure(err); - } -} - -} // namespace HomeLocationStruct - namespace LocationInfoStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { @@ -28019,6 +28019,230 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre namespace Events {} // namespace Events } // namespace ContentAppObserver +namespace EcosystemInformation { +namespace Structs { + +namespace EcosystemLocationStruct { +CHIP_ERROR Type::EncodeForWrite(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + return DoEncode(aWriter, aTag, NullOptional); +} + +CHIP_ERROR Type::EncodeForRead(TLV::TLVWriter & aWriter, TLV::Tag aTag, FabricIndex aAccessingFabricIndex) const +{ + return DoEncode(aWriter, aTag, MakeOptional(aAccessingFabricIndex)); +} + +CHIP_ERROR Type::DoEncode(TLV::TLVWriter & aWriter, TLV::Tag aTag, const Optional & aAccessingFabricIndex) const +{ + bool includeSensitive = !aAccessingFabricIndex.HasValue() || (aAccessingFabricIndex.Value() == fabricIndex); + + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kUniqueLocationID), uniqueLocationID); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kLocationDescriptor), locationDescriptor); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kLocationDescriptorLastEdit), locationDescriptorLastEdit); + } + if (aAccessingFabricIndex.HasValue()) + { + encoder.Encode(to_underlying(Fields::kFabricIndex), fabricIndex); + } + + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kUniqueLocationID)) + { + err = DataModel::Decode(reader, uniqueLocationID); + } + else if (__context_tag == to_underlying(Fields::kLocationDescriptor)) + { + err = DataModel::Decode(reader, locationDescriptor); + } + else if (__context_tag == to_underlying(Fields::kLocationDescriptorLastEdit)) + { + err = DataModel::Decode(reader, locationDescriptorLastEdit); + } + else if (__context_tag == to_underlying(Fields::kFabricIndex)) + { + err = DataModel::Decode(reader, fabricIndex); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} + +} // namespace EcosystemLocationStruct + +namespace EcosystemDeviceStruct { +CHIP_ERROR Type::EncodeForWrite(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + return DoEncode(aWriter, aTag, NullOptional); +} + +CHIP_ERROR Type::EncodeForRead(TLV::TLVWriter & aWriter, TLV::Tag aTag, FabricIndex aAccessingFabricIndex) const +{ + return DoEncode(aWriter, aTag, MakeOptional(aAccessingFabricIndex)); +} + +CHIP_ERROR Type::DoEncode(TLV::TLVWriter & aWriter, TLV::Tag aTag, const Optional & aAccessingFabricIndex) const +{ + bool includeSensitive = !aAccessingFabricIndex.HasValue() || (aAccessingFabricIndex.Value() == fabricIndex); + + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kDeviceName), deviceName); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kDeviceNameLastEdit), deviceNameLastEdit); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kBridgedEndpoint), bridgedEndpoint); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kOriginalEndpoint), originalEndpoint); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kDeviceTypes), deviceTypes); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kUniqueLocationIDs), uniqueLocationIDs); + } + if (includeSensitive) + { + encoder.Encode(to_underlying(Fields::kUniqueLocationIDsLastEdit), uniqueLocationIDsLastEdit); + } + if (aAccessingFabricIndex.HasValue()) + { + encoder.Encode(to_underlying(Fields::kFabricIndex), fabricIndex); + } + + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kDeviceName)) + { + err = DataModel::Decode(reader, deviceName); + } + else if (__context_tag == to_underlying(Fields::kDeviceNameLastEdit)) + { + err = DataModel::Decode(reader, deviceNameLastEdit); + } + else if (__context_tag == to_underlying(Fields::kBridgedEndpoint)) + { + err = DataModel::Decode(reader, bridgedEndpoint); + } + else if (__context_tag == to_underlying(Fields::kOriginalEndpoint)) + { + err = DataModel::Decode(reader, originalEndpoint); + } + else if (__context_tag == to_underlying(Fields::kDeviceTypes)) + { + err = DataModel::Decode(reader, deviceTypes); + } + else if (__context_tag == to_underlying(Fields::kUniqueLocationIDs)) + { + err = DataModel::Decode(reader, uniqueLocationIDs); + } + else if (__context_tag == to_underlying(Fields::kUniqueLocationIDsLastEdit)) + { + err = DataModel::Decode(reader, uniqueLocationIDsLastEdit); + } + else if (__context_tag == to_underlying(Fields::kFabricIndex)) + { + err = DataModel::Decode(reader, fabricIndex); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} + +} // namespace EcosystemDeviceStruct +} // namespace Structs + +namespace Commands {} // namespace Commands + +namespace Attributes { +CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path) +{ + switch (path.mAttributeId) + { + case Attributes::RemovedOn::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, removedOn); + case Attributes::DeviceDirectory::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, deviceDirectory); + case Attributes::LocationDirectory::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, locationDirectory); + case Attributes::GeneratedCommandList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, generatedCommandList); + case Attributes::AcceptedCommandList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, acceptedCommandList); + case Attributes::EventList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, eventList); + case Attributes::AttributeList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, attributeList); + case Attributes::FeatureMap::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, featureMap); + case Attributes::ClusterRevision::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, clusterRevision); + default: + return CHIP_NO_ERROR; + } +} +} // namespace Attributes + +namespace Events {} // namespace Events + +} // namespace EcosystemInformation namespace CommissionerControl { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 5952309732b90c..c99987215c8316 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -173,6 +173,54 @@ struct DecodableType }; } // namespace MeasurementAccuracyStruct +namespace HomeLocationStruct { +enum class Fields : uint8_t +{ + kLocationName = 0, + kFloorNumber = 1, + kAreaType = 2, +}; + +struct Type +{ +public: + chip::CharSpan locationName; + DataModel::Nullable floorNumber; + DataModel::Nullable areaType; + + CHIP_ERROR Decode(TLV::TLVReader & reader); + + static constexpr bool kIsFabricScoped = false; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; +}; + +using DecodableType = Type; + +} // namespace HomeLocationStruct +namespace DeviceTypeStruct { +enum class Fields : uint8_t +{ + kDeviceType = 0, + kRevision = 1, +}; + +struct Type +{ +public: + chip::DeviceTypeId deviceType = static_cast(0); + uint16_t revision = static_cast(0); + + CHIP_ERROR Decode(TLV::TLVReader & reader); + + static constexpr bool kIsFabricScoped = false; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; +}; + +using DecodableType = Type; + +} // namespace DeviceTypeStruct namespace ApplicationStruct { enum class Fields : uint8_t { @@ -2307,29 +2355,7 @@ struct TypeInfo } // namespace PulseWidthModulation namespace Descriptor { namespace Structs { -namespace DeviceTypeStruct { -enum class Fields : uint8_t -{ - kDeviceType = 0, - kRevision = 1, -}; - -struct Type -{ -public: - chip::DeviceTypeId deviceType = static_cast(0); - uint16_t revision = static_cast(0); - - CHIP_ERROR Decode(TLV::TLVReader & reader); - - static constexpr bool kIsFabricScoped = false; - - CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; -}; - -using DecodableType = Type; - -} // namespace DeviceTypeStruct +namespace DeviceTypeStruct = Clusters::detail::Structs::DeviceTypeStruct; namespace SemanticTagStruct { enum class Fields : uint8_t { @@ -27819,31 +27845,7 @@ struct TypeInfo } // namespace BarrierControl namespace ServiceArea { namespace Structs { -namespace HomeLocationStruct { -enum class Fields : uint8_t -{ - kLocationName = 0, - kFloorNumber = 1, - kAreaType = 2, -}; - -struct Type -{ -public: - chip::CharSpan locationName; - DataModel::Nullable floorNumber; - DataModel::Nullable areaType; - - CHIP_ERROR Decode(TLV::TLVReader & reader); - - static constexpr bool kIsFabricScoped = false; - - CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; -}; - -using DecodableType = Type; - -} // namespace HomeLocationStruct +namespace HomeLocationStruct = Clusters::detail::Structs::HomeLocationStruct; namespace LocationInfoStruct { enum class Fields : uint8_t { @@ -41172,6 +41174,208 @@ struct TypeInfo }; } // namespace Attributes } // namespace ContentAppObserver +namespace EcosystemInformation { +namespace Structs { +namespace HomeLocationStruct = Clusters::detail::Structs::HomeLocationStruct; +namespace EcosystemLocationStruct { +enum class Fields : uint8_t +{ + kUniqueLocationID = 0, + kLocationDescriptor = 1, + kLocationDescriptorLastEdit = 2, + kFabricIndex = 254, +}; + +struct Type +{ +public: + chip::CharSpan uniqueLocationID; + Structs::HomeLocationStruct::Type locationDescriptor; + uint64_t locationDescriptorLastEdit = static_cast(0); + chip::FabricIndex fabricIndex = static_cast(0); + + CHIP_ERROR Decode(TLV::TLVReader & reader); + + static constexpr bool kIsFabricScoped = true; + + auto GetFabricIndex() const { return fabricIndex; } + + void SetFabricIndex(chip::FabricIndex fabricIndex_) { fabricIndex = fabricIndex_; } + + CHIP_ERROR EncodeForWrite(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + CHIP_ERROR EncodeForRead(TLV::TLVWriter & aWriter, TLV::Tag aTag, FabricIndex aAccessingFabricIndex) const; + +private: + CHIP_ERROR DoEncode(TLV::TLVWriter & aWriter, TLV::Tag aTag, const Optional & aAccessingFabricIndex) const; +}; + +using DecodableType = Type; + +} // namespace EcosystemLocationStruct +namespace DeviceTypeStruct = Clusters::detail::Structs::DeviceTypeStruct; +namespace EcosystemDeviceStruct { +enum class Fields : uint8_t +{ + kDeviceName = 0, + kDeviceNameLastEdit = 1, + kBridgedEndpoint = 2, + kOriginalEndpoint = 3, + kDeviceTypes = 4, + kUniqueLocationIDs = 5, + kUniqueLocationIDsLastEdit = 6, + kFabricIndex = 254, +}; + +struct Type +{ +public: + Optional deviceName; + Optional deviceNameLastEdit; + chip::EndpointId bridgedEndpoint = static_cast(0); + chip::EndpointId originalEndpoint = static_cast(0); + DataModel::List deviceTypes; + DataModel::List uniqueLocationIDs; + uint64_t uniqueLocationIDsLastEdit = static_cast(0); + chip::FabricIndex fabricIndex = static_cast(0); + + static constexpr bool kIsFabricScoped = true; + + auto GetFabricIndex() const { return fabricIndex; } + + void SetFabricIndex(chip::FabricIndex fabricIndex_) { fabricIndex = fabricIndex_; } + + CHIP_ERROR EncodeForWrite(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + CHIP_ERROR EncodeForRead(TLV::TLVWriter & aWriter, TLV::Tag aTag, FabricIndex aAccessingFabricIndex) const; + +private: + CHIP_ERROR DoEncode(TLV::TLVWriter & aWriter, TLV::Tag aTag, const Optional & aAccessingFabricIndex) const; +}; + +struct DecodableType +{ +public: + Optional deviceName; + Optional deviceNameLastEdit; + chip::EndpointId bridgedEndpoint = static_cast(0); + chip::EndpointId originalEndpoint = static_cast(0); + DataModel::DecodableList deviceTypes; + DataModel::DecodableList uniqueLocationIDs; + uint64_t uniqueLocationIDsLastEdit = static_cast(0); + chip::FabricIndex fabricIndex = static_cast(0); + + CHIP_ERROR Decode(TLV::TLVReader & reader); + + static constexpr bool kIsFabricScoped = true; + + auto GetFabricIndex() const { return fabricIndex; } + + void SetFabricIndex(chip::FabricIndex fabricIndex_) { fabricIndex = fabricIndex_; } +}; + +} // namespace EcosystemDeviceStruct +} // namespace Structs + +namespace Attributes { + +namespace RemovedOn { +struct TypeInfo +{ + using Type = chip::app::DataModel::Nullable; + using DecodableType = chip::app::DataModel::Nullable; + using DecodableArgType = const chip::app::DataModel::Nullable &; + + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::RemovedOn::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace RemovedOn +namespace DeviceDirectory { +struct TypeInfo +{ + using Type = chip::app::DataModel::List; + using DecodableType = chip::app::DataModel::DecodableList< + chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::DecodableType>; + using DecodableArgType = const chip::app::DataModel::DecodableList< + chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::DecodableType> &; + + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::DeviceDirectory::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace DeviceDirectory +namespace LocationDirectory { +struct TypeInfo +{ + using Type = + chip::app::DataModel::List; + using DecodableType = chip::app::DataModel::DecodableList< + chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::DecodableType>; + using DecodableArgType = const chip::app::DataModel::DecodableList< + chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::DecodableType> &; + + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::LocationDirectory::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace LocationDirectory +namespace GeneratedCommandList { +struct TypeInfo : public Clusters::Globals::Attributes::GeneratedCommandList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } +}; +} // namespace GeneratedCommandList +namespace AcceptedCommandList { +struct TypeInfo : public Clusters::Globals::Attributes::AcceptedCommandList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } +}; +} // namespace AcceptedCommandList +namespace EventList { +struct TypeInfo : public Clusters::Globals::Attributes::EventList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } +}; +} // namespace EventList +namespace AttributeList { +struct TypeInfo : public Clusters::Globals::Attributes::AttributeList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } +}; +} // namespace AttributeList +namespace FeatureMap { +struct TypeInfo : public Clusters::Globals::Attributes::FeatureMap::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } +}; +} // namespace FeatureMap +namespace ClusterRevision { +struct TypeInfo : public Clusters::Globals::Attributes::ClusterRevision::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } +}; +} // namespace ClusterRevision + +struct TypeInfo +{ + struct DecodableType + { + static constexpr ClusterId GetClusterId() { return Clusters::EcosystemInformation::Id; } + + CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path); + + Attributes::RemovedOn::TypeInfo::DecodableType removedOn; + Attributes::DeviceDirectory::TypeInfo::DecodableType deviceDirectory; + Attributes::LocationDirectory::TypeInfo::DecodableType locationDirectory; + Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; + Attributes::AcceptedCommandList::TypeInfo::DecodableType acceptedCommandList; + Attributes::EventList::TypeInfo::DecodableType eventList; + Attributes::AttributeList::TypeInfo::DecodableType attributeList; + Attributes::FeatureMap::TypeInfo::DecodableType featureMap = static_cast(0); + Attributes::ClusterRevision::TypeInfo::DecodableType clusterRevision = static_cast(0); + }; +}; +} // namespace Attributes +} // namespace EcosystemInformation namespace CommissionerControl { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index 224f09ff69f44d..c1d26d64c5d27b 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -7459,6 +7459,48 @@ static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; } // namespace Attributes } // namespace ContentAppObserver +namespace EcosystemInformation { +namespace Attributes { + +namespace RemovedOn { +static constexpr AttributeId Id = 0x00000000; +} // namespace RemovedOn + +namespace DeviceDirectory { +static constexpr AttributeId Id = 0x00000001; +} // namespace DeviceDirectory + +namespace LocationDirectory { +static constexpr AttributeId Id = 0x00000002; +} // namespace LocationDirectory + +namespace GeneratedCommandList { +static constexpr AttributeId Id = Globals::Attributes::GeneratedCommandList::Id; +} // namespace GeneratedCommandList + +namespace AcceptedCommandList { +static constexpr AttributeId Id = Globals::Attributes::AcceptedCommandList::Id; +} // namespace AcceptedCommandList + +namespace EventList { +static constexpr AttributeId Id = Globals::Attributes::EventList::Id; +} // namespace EventList + +namespace AttributeList { +static constexpr AttributeId Id = Globals::Attributes::AttributeList::Id; +} // namespace AttributeList + +namespace FeatureMap { +static constexpr AttributeId Id = Globals::Attributes::FeatureMap::Id; +} // namespace FeatureMap + +namespace ClusterRevision { +static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace EcosystemInformation + namespace CommissionerControl { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h index b94e6c1772f2aa..9e5bb87b52ef51 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h @@ -385,6 +385,9 @@ static constexpr ClusterId Id = 0x0000050F; namespace ContentAppObserver { static constexpr ClusterId Id = 0x00000510; } // namespace ContentAppObserver +namespace EcosystemInformation { +static constexpr ClusterId Id = 0x00000750; +} // namespace EcosystemInformation namespace CommissionerControl { static constexpr ClusterId Id = 0x00000751; } // namespace CommissionerControl diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 99221c08e3f71c..273f743a19cf00 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -155,6 +155,7 @@ | AccountLogin | 0x050E | | ContentControl | 0x050F | | ContentAppObserver | 0x0510 | +| EcosystemInformation | 0x0750 | | CommissionerControl | 0x0751 | | ElectricalMeasurement | 0x0B04 | | UnitTesting | 0xFFF1FC05| @@ -13814,6 +13815,25 @@ class ContentAppObserverContentAppMessage : public ClusterCommand chip::app::Clusters::ContentAppObserver::Commands::ContentAppMessage::Type mRequest; }; +/*----------------------------------------------------------------------------*\ +| Cluster EcosystemInformation | 0x0750 | +|------------------------------------------------------------------------------| +| Commands: | | +|------------------------------------------------------------------------------| +| Attributes: | | +| * RemovedOn | 0x0000 | +| * DeviceDirectory | 0x0001 | +| * LocationDirectory | 0x0002 | +| * GeneratedCommandList | 0xFFF8 | +| * AcceptedCommandList | 0xFFF9 | +| * EventList | 0xFFFA | +| * AttributeList | 0xFFFB | +| * FeatureMap | 0xFFFC | +| * ClusterRevision | 0xFFFD | +|------------------------------------------------------------------------------| +| Events: | | +\*----------------------------------------------------------------------------*/ + /*----------------------------------------------------------------------------*\ | Cluster CommissionerControl | 0x0751 | |------------------------------------------------------------------------------| @@ -26701,6 +26721,71 @@ void registerClusterContentAppObserver(Commands & commands, CredentialIssuerComm commands.RegisterCluster(clusterName, clusterCommands); } +void registerClusterEcosystemInformation(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) +{ + using namespace chip::app::Clusters::EcosystemInformation; + + const char * clusterName = "EcosystemInformation"; + + commands_list clusterCommands = { + // + // Commands + // + make_unique(Id, credsIssuerConfig), // + // + // Attributes + // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "removed-on", Attributes::RemovedOn::Id, credsIssuerConfig), // + make_unique(Id, "device-directory", Attributes::DeviceDirectory::Id, credsIssuerConfig), // + make_unique(Id, "location-directory", Attributes::LocationDirectory::Id, credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + make_unique>(Id, credsIssuerConfig), // + make_unique>>( + Id, "removed-on", 0, UINT64_MAX, Attributes::RemovedOn::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "device-directory", Attributes::DeviceDirectory::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "location-directory", Attributes::LocationDirectory::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "generated-command-list", Attributes::GeneratedCommandList::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>>( + Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "event-list", Attributes::EventList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "attribute-list", Attributes::AttributeList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>(Id, "feature-map", 0, UINT32_MAX, Attributes::FeatureMap::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>(Id, "cluster-revision", 0, UINT16_MAX, Attributes::ClusterRevision::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "removed-on", Attributes::RemovedOn::Id, credsIssuerConfig), // + make_unique(Id, "device-directory", Attributes::DeviceDirectory::Id, credsIssuerConfig), // + make_unique(Id, "location-directory", Attributes::LocationDirectory::Id, credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + // + // Events + // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + }; + + commands.RegisterCluster(clusterName, clusterCommands); +} void registerClusterCommissionerControl(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) { using namespace chip::app::Clusters::CommissionerControl; @@ -28174,6 +28259,7 @@ void registerClusters(Commands & commands, CredentialIssuerCommands * credsIssue registerClusterAccountLogin(commands, credsIssuerConfig); registerClusterContentControl(commands, credsIssuerConfig); registerClusterContentAppObserver(commands, credsIssuerConfig); + registerClusterEcosystemInformation(commands, credsIssuerConfig); registerClusterCommissionerControl(commands, credsIssuerConfig); registerClusterElectricalMeasurement(commands, credsIssuerConfig); registerClusterUnitTesting(commands, credsIssuerConfig); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp index c6d7864443fafe..d78bc468849928 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp @@ -219,6 +219,76 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::detail::Structs::Measu ComplexArgumentParser::Finalize(request.accuracyRanges); } +CHIP_ERROR ComplexArgumentParser::Setup(const char * label, + chip::app::Clusters::detail::Structs::HomeLocationStruct::Type & request, + Json::Value & value) +{ + VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); + + // Copy to track which members we already processed. + Json::Value valueCopy(value); + + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("HomeLocationStruct.locationName", "locationName", + value.isMember("locationName"))); + ReturnErrorOnFailure( + ComplexArgumentParser::EnsureMemberExist("HomeLocationStruct.floorNumber", "floorNumber", value.isMember("floorNumber"))); + ReturnErrorOnFailure( + ComplexArgumentParser::EnsureMemberExist("HomeLocationStruct.areaType", "areaType", value.isMember("areaType"))); + + char labelWithMember[kMaxLabelLength]; + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationName"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.locationName, value["locationName"])); + valueCopy.removeMember("locationName"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "floorNumber"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.floorNumber, value["floorNumber"])); + valueCopy.removeMember("floorNumber"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "areaType"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.areaType, value["areaType"])); + valueCopy.removeMember("areaType"); + + return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); +} + +void ComplexArgumentParser::Finalize(chip::app::Clusters::detail::Structs::HomeLocationStruct::Type & request) +{ + ComplexArgumentParser::Finalize(request.locationName); + ComplexArgumentParser::Finalize(request.floorNumber); + ComplexArgumentParser::Finalize(request.areaType); +} + +CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::detail::Structs::DeviceTypeStruct::Type & request, + Json::Value & value) +{ + VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); + + // Copy to track which members we already processed. + Json::Value valueCopy(value); + + ReturnErrorOnFailure( + ComplexArgumentParser::EnsureMemberExist("DeviceTypeStruct.deviceType", "deviceType", value.isMember("deviceType"))); + ReturnErrorOnFailure( + ComplexArgumentParser::EnsureMemberExist("DeviceTypeStruct.revision", "revision", value.isMember("revision"))); + + char labelWithMember[kMaxLabelLength]; + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "deviceType"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.deviceType, value["deviceType"])); + valueCopy.removeMember("deviceType"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "revision"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.revision, value["revision"])); + valueCopy.removeMember("revision"); + + return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); +} + +void ComplexArgumentParser::Finalize(chip::app::Clusters::detail::Structs::DeviceTypeStruct::Type & request) +{ + ComplexArgumentParser::Finalize(request.deviceType); + ComplexArgumentParser::Finalize(request.revision); +} + CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::detail::Structs::ApplicationStruct::Type & request, Json::Value & value) { @@ -353,38 +423,6 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::detail::Structs::Opera ComplexArgumentParser::Finalize(request.operationalStateLabel); } -CHIP_ERROR ComplexArgumentParser::Setup(const char * label, - chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::Type & request, - Json::Value & value) -{ - VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); - - // Copy to track which members we already processed. - Json::Value valueCopy(value); - - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("DeviceTypeStruct.deviceType", "deviceType", value.isMember("deviceType"))); - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("DeviceTypeStruct.revision", "revision", value.isMember("revision"))); - - char labelWithMember[kMaxLabelLength]; - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "deviceType"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.deviceType, value["deviceType"])); - valueCopy.removeMember("deviceType"); - - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "revision"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.revision, value["revision"])); - valueCopy.removeMember("revision"); - - return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); -} - -void ComplexArgumentParser::Finalize(chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::Type & request) -{ - ComplexArgumentParser::Finalize(request.deviceType); - ComplexArgumentParser::Finalize(request.revision); -} - CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::Descriptor::Structs::SemanticTagStruct::Type & request, Json::Value & value) @@ -3748,45 +3786,6 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::DoorLock::Structs::Cre ComplexArgumentParser::Finalize(request.credentialIndex); } -CHIP_ERROR ComplexArgumentParser::Setup(const char * label, - chip::app::Clusters::ServiceArea::Structs::HomeLocationStruct::Type & request, - Json::Value & value) -{ - VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); - - // Copy to track which members we already processed. - Json::Value valueCopy(value); - - ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("HomeLocationStruct.locationName", "locationName", - value.isMember("locationName"))); - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("HomeLocationStruct.floorNumber", "floorNumber", value.isMember("floorNumber"))); - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("HomeLocationStruct.areaType", "areaType", value.isMember("areaType"))); - - char labelWithMember[kMaxLabelLength]; - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationName"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.locationName, value["locationName"])); - valueCopy.removeMember("locationName"); - - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "floorNumber"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.floorNumber, value["floorNumber"])); - valueCopy.removeMember("floorNumber"); - - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "areaType"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.areaType, value["areaType"])); - valueCopy.removeMember("areaType"); - - return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); -} - -void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs::HomeLocationStruct::Type & request) -{ - ComplexArgumentParser::Finalize(request.locationName); - ComplexArgumentParser::Finalize(request.floorNumber); - ComplexArgumentParser::Finalize(request.areaType); -} - CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::Type & request, Json::Value & value) @@ -5405,6 +5404,135 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::ContentControl::Struct ComplexArgumentParser::Finalize(request.ratingNameDesc); } +CHIP_ERROR ComplexArgumentParser::Setup(const char * label, + chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::Type & request, + Json::Value & value) +{ + VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); + + // Copy to track which members we already processed. + Json::Value valueCopy(value); + + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemLocationStruct.uniqueLocationID", "uniqueLocationID", + value.isMember("uniqueLocationID"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemLocationStruct.locationDescriptor", + "locationDescriptor", value.isMember("locationDescriptor"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemLocationStruct.locationDescriptorLastEdit", + "locationDescriptorLastEdit", + value.isMember("locationDescriptorLastEdit"))); + + char labelWithMember[kMaxLabelLength]; + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "uniqueLocationID"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.uniqueLocationID, value["uniqueLocationID"])); + valueCopy.removeMember("uniqueLocationID"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationDescriptor"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.locationDescriptor, value["locationDescriptor"])); + valueCopy.removeMember("locationDescriptor"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationDescriptorLastEdit"); + ReturnErrorOnFailure( + ComplexArgumentParser::Setup(labelWithMember, request.locationDescriptorLastEdit, value["locationDescriptorLastEdit"])); + valueCopy.removeMember("locationDescriptorLastEdit"); + + if (value.isMember("fabricIndex")) + { + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "fabricIndex"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.fabricIndex, value["fabricIndex"])); + } + valueCopy.removeMember("fabricIndex"); + + return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); +} + +void ComplexArgumentParser::Finalize(chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::Type & request) +{ + ComplexArgumentParser::Finalize(request.uniqueLocationID); + ComplexArgumentParser::Finalize(request.locationDescriptor); + ComplexArgumentParser::Finalize(request.locationDescriptorLastEdit); + ComplexArgumentParser::Finalize(request.fabricIndex); +} + +CHIP_ERROR ComplexArgumentParser::Setup(const char * label, + chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::Type & request, + Json::Value & value) +{ + VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); + + // Copy to track which members we already processed. + Json::Value valueCopy(value); + + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemDeviceStruct.bridgedEndpoint", "bridgedEndpoint", + value.isMember("bridgedEndpoint"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemDeviceStruct.originalEndpoint", "originalEndpoint", + value.isMember("originalEndpoint"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemDeviceStruct.deviceTypes", "deviceTypes", + value.isMember("deviceTypes"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemDeviceStruct.uniqueLocationIDs", "uniqueLocationIDs", + value.isMember("uniqueLocationIDs"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("EcosystemDeviceStruct.uniqueLocationIDsLastEdit", + "uniqueLocationIDsLastEdit", + value.isMember("uniqueLocationIDsLastEdit"))); + + char labelWithMember[kMaxLabelLength]; + if (value.isMember("deviceName")) + { + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "deviceName"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.deviceName, value["deviceName"])); + } + valueCopy.removeMember("deviceName"); + + if (value.isMember("deviceNameLastEdit")) + { + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "deviceNameLastEdit"); + ReturnErrorOnFailure( + ComplexArgumentParser::Setup(labelWithMember, request.deviceNameLastEdit, value["deviceNameLastEdit"])); + } + valueCopy.removeMember("deviceNameLastEdit"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "bridgedEndpoint"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.bridgedEndpoint, value["bridgedEndpoint"])); + valueCopy.removeMember("bridgedEndpoint"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "originalEndpoint"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.originalEndpoint, value["originalEndpoint"])); + valueCopy.removeMember("originalEndpoint"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "deviceTypes"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.deviceTypes, value["deviceTypes"])); + valueCopy.removeMember("deviceTypes"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "uniqueLocationIDs"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.uniqueLocationIDs, value["uniqueLocationIDs"])); + valueCopy.removeMember("uniqueLocationIDs"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "uniqueLocationIDsLastEdit"); + ReturnErrorOnFailure( + ComplexArgumentParser::Setup(labelWithMember, request.uniqueLocationIDsLastEdit, value["uniqueLocationIDsLastEdit"])); + valueCopy.removeMember("uniqueLocationIDsLastEdit"); + + if (value.isMember("fabricIndex")) + { + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "fabricIndex"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.fabricIndex, value["fabricIndex"])); + } + valueCopy.removeMember("fabricIndex"); + + return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); +} + +void ComplexArgumentParser::Finalize(chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::Type & request) +{ + ComplexArgumentParser::Finalize(request.deviceName); + ComplexArgumentParser::Finalize(request.deviceNameLastEdit); + ComplexArgumentParser::Finalize(request.bridgedEndpoint); + ComplexArgumentParser::Finalize(request.originalEndpoint); + ComplexArgumentParser::Finalize(request.deviceTypes); + ComplexArgumentParser::Finalize(request.uniqueLocationIDs); + ComplexArgumentParser::Finalize(request.uniqueLocationIDsLastEdit); + ComplexArgumentParser::Finalize(request.fabricIndex); +} + CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::UnitTesting::Structs::SimpleStruct::Type & request, Json::Value & value) { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h index c258467efab2a6..f777963970303c 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h @@ -42,6 +42,16 @@ static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs static void Finalize(chip::app::Clusters::detail::Structs::MeasurementAccuracyStruct::Type & request); +static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs::HomeLocationStruct::Type & request, + Json::Value & value); + +static void Finalize(chip::app::Clusters::detail::Structs::HomeLocationStruct::Type & request); + +static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs::DeviceTypeStruct::Type & request, + Json::Value & value); + +static void Finalize(chip::app::Clusters::detail::Structs::DeviceTypeStruct::Type & request); + static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs::ApplicationStruct::Type & request, Json::Value & value); @@ -61,11 +71,6 @@ static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs static void Finalize(chip::app::Clusters::detail::Structs::OperationalStateStruct::Type & request); -static CHIP_ERROR Setup(const char * label, chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::Type & request, - Json::Value & value); - -static void Finalize(chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::Type & request); - static CHIP_ERROR Setup(const char * label, chip::app::Clusters::Descriptor::Structs::SemanticTagStruct::Type & request, Json::Value & value); @@ -426,11 +431,6 @@ static CHIP_ERROR Setup(const char * label, chip::app::Clusters::DoorLock::Struc static void Finalize(chip::app::Clusters::DoorLock::Structs::CredentialStruct::Type & request); -static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::HomeLocationStruct::Type & request, - Json::Value & value); - -static void Finalize(chip::app::Clusters::ServiceArea::Structs::HomeLocationStruct::Type & request); - static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::Type & request, Json::Value & value); @@ -620,6 +620,18 @@ static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ContentControl: static void Finalize(chip::app::Clusters::ContentControl::Structs::RatingNameStruct::Type & request); +static CHIP_ERROR Setup(const char * label, + chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::Type & request, + Json::Value & value); + +static void Finalize(chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::Type & request); + +static CHIP_ERROR Setup(const char * label, + chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::Type & request, + Json::Value & value); + +static void Finalize(chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::Type & request); + static CHIP_ERROR Setup(const char * label, chip::app::Clusters::UnitTesting::Structs::SimpleStruct::Type & request, Json::Value & value); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index 5071a49a141e51..1fade3e28c9c22 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -202,6 +202,64 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const chip::app::Clusters::detail::Structs::HomeLocationStruct::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = LogValue("LocationName", indent + 1, value.locationName); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationName'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("FloorNumber", indent + 1, value.floorNumber); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'FloorNumber'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("AreaType", indent + 1, value.areaType); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'AreaType'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const chip::app::Clusters::detail::Structs::DeviceTypeStruct::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = LogValue("DeviceType", indent + 1, value.deviceType); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'DeviceType'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("Revision", indent + 1, value.revision); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'Revision'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} + CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::ApplicationStruct::DecodableType & value) { @@ -310,31 +368,6 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } -CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::DecodableType & value) -{ - DataModelLogger::LogString(label, indent, "{"); - { - CHIP_ERROR err = LogValue("DeviceType", indent + 1, value.deviceType); - if (err != CHIP_NO_ERROR) - { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'DeviceType'"); - return err; - } - } - { - CHIP_ERROR err = LogValue("Revision", indent + 1, value.revision); - if (err != CHIP_NO_ERROR) - { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'Revision'"); - return err; - } - } - DataModelLogger::LogString(indent, "}"); - - return CHIP_NO_ERROR; -} - CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const chip::app::Clusters::Descriptor::Structs::SemanticTagStruct::DecodableType & value) { @@ -3321,39 +3354,6 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } -CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Structs::HomeLocationStruct::DecodableType & value) -{ - DataModelLogger::LogString(label, indent, "{"); - { - CHIP_ERROR err = LogValue("LocationName", indent + 1, value.locationName); - if (err != CHIP_NO_ERROR) - { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationName'"); - return err; - } - } - { - CHIP_ERROR err = LogValue("FloorNumber", indent + 1, value.floorNumber); - if (err != CHIP_NO_ERROR) - { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'FloorNumber'"); - return err; - } - } - { - CHIP_ERROR err = LogValue("AreaType", indent + 1, value.areaType); - if (err != CHIP_NO_ERROR) - { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'AreaType'"); - return err; - } - } - DataModelLogger::LogString(indent, "}"); - - return CHIP_NO_ERROR; -} - CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::DecodableType & value) { @@ -4764,6 +4764,122 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } +CHIP_ERROR +DataModelLogger::LogValue(const char * label, size_t indent, + const chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = LogValue("UniqueLocationID", indent + 1, value.uniqueLocationID); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'UniqueLocationID'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("LocationDescriptor", indent + 1, value.locationDescriptor); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationDescriptor'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("LocationDescriptorLastEdit", indent + 1, value.locationDescriptorLastEdit); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationDescriptorLastEdit'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("FabricIndex", indent + 1, value.fabricIndex); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'FabricIndex'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +DataModelLogger::LogValue(const char * label, size_t indent, + const chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = LogValue("DeviceName", indent + 1, value.deviceName); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'DeviceName'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("DeviceNameLastEdit", indent + 1, value.deviceNameLastEdit); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'DeviceNameLastEdit'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("BridgedEndpoint", indent + 1, value.bridgedEndpoint); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'BridgedEndpoint'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("OriginalEndpoint", indent + 1, value.originalEndpoint); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'OriginalEndpoint'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("DeviceTypes", indent + 1, value.deviceTypes); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'DeviceTypes'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("UniqueLocationIDs", indent + 1, value.uniqueLocationIDs); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'UniqueLocationIDs'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("UniqueLocationIDsLastEdit", indent + 1, value.uniqueLocationIDsLastEdit); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'UniqueLocationIDsLastEdit'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("FabricIndex", indent + 1, value.fabricIndex); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'FabricIndex'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} + CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const chip::app::Clusters::UnitTesting::Structs::SimpleStruct::DecodableType & value) { @@ -17627,6 +17743,61 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP } break; } + case EcosystemInformation::Id: { + switch (path.mAttributeId) + { + case EcosystemInformation::Attributes::RemovedOn::Id: { + chip::app::DataModel::Nullable value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("RemovedOn", 1, value); + } + case EcosystemInformation::Attributes::DeviceDirectory::Id: { + chip::app::DataModel::DecodableList< + chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::DecodableType> + value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("DeviceDirectory", 1, value); + } + case EcosystemInformation::Attributes::LocationDirectory::Id: { + chip::app::DataModel::DecodableList< + chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::DecodableType> + value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("LocationDirectory", 1, value); + } + case EcosystemInformation::Attributes::GeneratedCommandList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("GeneratedCommandList", 1, value); + } + case EcosystemInformation::Attributes::AcceptedCommandList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AcceptedCommandList", 1, value); + } + case EcosystemInformation::Attributes::EventList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("EventList", 1, value); + } + case EcosystemInformation::Attributes::AttributeList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AttributeList", 1, value); + } + case EcosystemInformation::Attributes::FeatureMap::Id: { + uint32_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("FeatureMap", 1, value); + } + case EcosystemInformation::Attributes::ClusterRevision::Id: { + uint16_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("ClusterRevision", 1, value); + } + } + break; + } case CommissionerControl::Id: { switch (path.mAttributeId) { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index 95cc96d293b574..7680e14c314316 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -32,6 +32,12 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::MeasurementAccuracyStruct::DecodableType & value); +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::detail::Structs::HomeLocationStruct::DecodableType & value); + +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::detail::Structs::DeviceTypeStruct::DecodableType & value); + static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::ApplicationStruct::DecodableType & value); @@ -44,9 +50,6 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::OperationalStateStruct::DecodableType & value); -static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::DecodableType & value); - static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::Descriptor::Structs::SemanticTagStruct::DecodableType & value); @@ -267,9 +270,6 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::DoorLock::Structs::CredentialStruct::DecodableType & value); -static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Structs::HomeLocationStruct::DecodableType & value); - static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::DecodableType & value); @@ -381,6 +381,13 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ContentControl::Structs::RatingNameStruct::DecodableType & value); +static CHIP_ERROR +LogValue(const char * label, size_t indent, + const chip::app::Clusters::EcosystemInformation::Structs::EcosystemLocationStruct::DecodableType & value); + +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::EcosystemInformation::Structs::EcosystemDeviceStruct::DecodableType & value); + static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::UnitTesting::Structs::SimpleStruct::DecodableType & value); diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 17451309d1e621..8ebe6735d29dd0 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -157,6 +157,7 @@ | AccountLogin | 0x050E | | ContentControl | 0x050F | | ContentAppObserver | 0x0510 | +| EcosystemInformation | 0x0750 | | CommissionerControl | 0x0751 | | ElectricalMeasurement | 0x0B04 | | UnitTesting | 0xFFF1FC05| @@ -163290,6 +163291,800 @@ class SubscribeAttributeContentAppObserverClusterRevision : public SubscribeAttr } }; +#endif // MTR_ENABLE_PROVISIONAL +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL +/*----------------------------------------------------------------------------*\ +| Cluster EcosystemInformation | 0x0750 | +|------------------------------------------------------------------------------| +| Commands: | | +|------------------------------------------------------------------------------| +| Attributes: | | +| * RemovedOn | 0x0000 | +| * DeviceDirectory | 0x0001 | +| * LocationDirectory | 0x0002 | +| * GeneratedCommandList | 0xFFF8 | +| * AcceptedCommandList | 0xFFF9 | +| * EventList | 0xFFFA | +| * AttributeList | 0xFFFB | +| * FeatureMap | 0xFFFC | +| * ClusterRevision | 0xFFFD | +|------------------------------------------------------------------------------| +| Events: | | +\*----------------------------------------------------------------------------*/ + +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute RemovedOn + */ +class ReadEcosystemInformationRemovedOn : public ReadAttribute { +public: + ReadEcosystemInformationRemovedOn() + : ReadAttribute("removed-on") + { + } + + ~ReadEcosystemInformationRemovedOn() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::RemovedOn::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeRemovedOnWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.RemovedOn response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation RemovedOn read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationRemovedOn : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationRemovedOn() + : SubscribeAttribute("removed-on") + { + } + + ~SubscribeAttributeEcosystemInformationRemovedOn() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::RemovedOn::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeRemovedOnWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.RemovedOn response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute DeviceDirectory + */ +class ReadEcosystemInformationDeviceDirectory : public ReadAttribute { +public: + ReadEcosystemInformationDeviceDirectory() + : ReadAttribute("device-directory") + { + } + + ~ReadEcosystemInformationDeviceDirectory() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::DeviceDirectory::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRReadParams alloc] init]; + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + [cluster readAttributeDeviceDirectoryWithParams:params completion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.DeviceDirectory response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation DeviceDirectory read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationDeviceDirectory : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationDeviceDirectory() + : SubscribeAttribute("device-directory") + { + } + + ~SubscribeAttributeEcosystemInformationDeviceDirectory() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::DeviceDirectory::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeDeviceDirectoryWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.DeviceDirectory response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute LocationDirectory + */ +class ReadEcosystemInformationLocationDirectory : public ReadAttribute { +public: + ReadEcosystemInformationLocationDirectory() + : ReadAttribute("location-directory") + { + } + + ~ReadEcosystemInformationLocationDirectory() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::LocationDirectory::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRReadParams alloc] init]; + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + [cluster readAttributeLocationDirectoryWithParams:params completion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.LocationDirectory response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation LocationDirectory read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationLocationDirectory : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationLocationDirectory() + : SubscribeAttribute("location-directory") + { + } + + ~SubscribeAttributeEcosystemInformationLocationDirectory() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::LocationDirectory::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeLocationDirectoryWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.LocationDirectory response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute GeneratedCommandList + */ +class ReadEcosystemInformationGeneratedCommandList : public ReadAttribute { +public: + ReadEcosystemInformationGeneratedCommandList() + : ReadAttribute("generated-command-list") + { + } + + ~ReadEcosystemInformationGeneratedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::GeneratedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeGeneratedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.GeneratedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation GeneratedCommandList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationGeneratedCommandList : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationGeneratedCommandList() + : SubscribeAttribute("generated-command-list") + { + } + + ~SubscribeAttributeEcosystemInformationGeneratedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::GeneratedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeGeneratedCommandListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.GeneratedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AcceptedCommandList + */ +class ReadEcosystemInformationAcceptedCommandList : public ReadAttribute { +public: + ReadEcosystemInformationAcceptedCommandList() + : ReadAttribute("accepted-command-list") + { + } + + ~ReadEcosystemInformationAcceptedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::AcceptedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAcceptedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.AcceptedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation AcceptedCommandList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationAcceptedCommandList : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationAcceptedCommandList() + : SubscribeAttribute("accepted-command-list") + { + } + + ~SubscribeAttributeEcosystemInformationAcceptedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::AcceptedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAcceptedCommandListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.AcceptedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute EventList + */ +class ReadEcosystemInformationEventList : public ReadAttribute { +public: + ReadEcosystemInformationEventList() + : ReadAttribute("event-list") + { + } + + ~ReadEcosystemInformationEventList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::EventList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeEventListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.EventList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation EventList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationEventList : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationEventList() + : SubscribeAttribute("event-list") + { + } + + ~SubscribeAttributeEcosystemInformationEventList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::EventList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeEventListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.EventList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AttributeList + */ +class ReadEcosystemInformationAttributeList : public ReadAttribute { +public: + ReadEcosystemInformationAttributeList() + : ReadAttribute("attribute-list") + { + } + + ~ReadEcosystemInformationAttributeList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::AttributeList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAttributeListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.AttributeList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation AttributeList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationAttributeList : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationAttributeList() + : SubscribeAttribute("attribute-list") + { + } + + ~SubscribeAttributeEcosystemInformationAttributeList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::AttributeList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAttributeListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.AttributeList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute FeatureMap + */ +class ReadEcosystemInformationFeatureMap : public ReadAttribute { +public: + ReadEcosystemInformationFeatureMap() + : ReadAttribute("feature-map") + { + } + + ~ReadEcosystemInformationFeatureMap() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::FeatureMap::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeFeatureMapWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.FeatureMap response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation FeatureMap read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationFeatureMap : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationFeatureMap() + : SubscribeAttribute("feature-map") + { + } + + ~SubscribeAttributeEcosystemInformationFeatureMap() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::FeatureMap::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeFeatureMapWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.FeatureMap response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute ClusterRevision + */ +class ReadEcosystemInformationClusterRevision : public ReadAttribute { +public: + ReadEcosystemInformationClusterRevision() + : ReadAttribute("cluster-revision") + { + } + + ~ReadEcosystemInformationClusterRevision() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::ClusterRevision::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeClusterRevisionWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.ClusterRevision response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("EcosystemInformation ClusterRevision read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeEcosystemInformationClusterRevision : public SubscribeAttribute { +public: + SubscribeAttributeEcosystemInformationClusterRevision() + : SubscribeAttribute("cluster-revision") + { + } + + ~SubscribeAttributeEcosystemInformationClusterRevision() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::EcosystemInformation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::EcosystemInformation::Attributes::ClusterRevision::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterEcosystemInformation alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeClusterRevisionWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"EcosystemInformation.ClusterRevision response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + #endif // MTR_ENABLE_PROVISIONAL #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL @@ -196257,6 +197052,59 @@ void registerClusterContentAppObserver(Commands & commands) commands.RegisterCluster(clusterName, clusterCommands); #endif // MTR_ENABLE_PROVISIONAL } +void registerClusterEcosystemInformation(Commands & commands) +{ +#if MTR_ENABLE_PROVISIONAL + using namespace chip::app::Clusters::EcosystemInformation; + + const char * clusterName = "EcosystemInformation"; + + commands_list clusterCommands = { + make_unique(Id), // + make_unique(Id), // + make_unique(Id), // + make_unique(Id), // +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL + }; + + commands.RegisterCluster(clusterName, clusterCommands); +#endif // MTR_ENABLE_PROVISIONAL +} void registerClusterCommissionerControl(Commands & commands) { #if MTR_ENABLE_PROVISIONAL @@ -197113,6 +197961,7 @@ void registerClusters(Commands & commands) registerClusterAccountLogin(commands); registerClusterContentControl(commands); registerClusterContentAppObserver(commands); + registerClusterEcosystemInformation(commands); registerClusterCommissionerControl(commands); registerClusterElectricalMeasurement(commands); registerClusterUnitTesting(commands); From 7d26280fc68780ae799a3325dd1db78b20d38874 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 26 Jul 2024 06:13:58 +0200 Subject: [PATCH 16/17] Implements the Commissioner Control Cluster in Matter SDK (#34375) Co-authored-by: Terence Hampson Co-authored-by: Boris Zbarsky Co-authored-by: Restyled.io --- .../fabric-bridge-app.matter | 66 +++++ .../fabric-bridge-app.zap | 158 +++++++++++ .../commissioner-control-server.cpp | 268 ++++++++++++++++++ .../commissioner-control-server.h | 182 ++++++++++++ 4 files changed, 674 insertions(+) create mode 100644 src/app/clusters/commissioner-control-server/commissioner-control-server.cpp create mode 100644 src/app/clusters/commissioner-control-server/commissioner-control-server.h diff --git a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter index 7f3de425528f64..46bd51d578e6ee 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter +++ b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter @@ -1334,6 +1334,57 @@ cluster GroupKeyManagement = 63 { fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; } +/** Supports the ability for clients to request the commissioning of themselves or other nodes onto a fabric which the cluster server can commission onto. */ +provisional cluster CommissionerControl = 1873 { + revision 1; + + bitmap SupportedDeviceCategoryBitmap : bitmap32 { + kFabricSynchronization = 0x1; + } + + fabric_sensitive info event access(read: manage) CommissioningRequestResult = 0 { + int64u requestId = 0; + node_id clientNodeId = 1; + enum8 statusCode = 2; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: manage) SupportedDeviceCategoryBitmap supportedDeviceCategories = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct RequestCommissioningApprovalRequest { + int64u requestId = 0; + vendor_id vendorId = 1; + int16u productId = 2; + optional char_string<64> label = 3; + } + + request struct CommissionNodeRequest { + int64u requestId = 0; + int16u responseTimeoutSeconds = 1; + optional octet_string ipAddress = 2; + optional int16u port = 3; + } + + response struct ReverseOpenCommissioningWindow = 2 { + int16u commissioningTimeout = 0; + octet_string PAKEPasscodeVerifier = 1; + int16u discriminator = 2; + int32u iterations = 3; + octet_string<32> salt = 4; + } + + /** This command is sent by a client to request approval for a future CommissionNode call. */ + command access(invoke: manage) RequestCommissioningApproval(RequestCommissioningApprovalRequest): DefaultSuccess = 0; + /** This command is sent by a client to request that the server begins commissioning a previously approved request. */ + command access(invoke: manage) CommissionNode(CommissionNodeRequest): ReverseOpenCommissioningWindow = 1; +} + endpoint 0 { device type ma_rootdevice = 22, version 1; @@ -1647,6 +1698,21 @@ endpoint 0 { handle command KeySetReadAllIndices; handle command KeySetReadAllIndicesResponse; } + + server cluster CommissionerControl { + emits event CommissioningRequestResult; + ram attribute supportedDeviceCategories default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command RequestCommissioningApproval; + handle command CommissionNode; + handle command ReverseOpenCommissioningWindow; + } } endpoint 1 { device type ma_aggregator = 14, version 1; diff --git a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.zap b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.zap index cbf31a039b85ee..6345745cde4fce 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.zap +++ b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.zap @@ -4003,6 +4003,164 @@ "reportableChange": 0 } ] + }, + { + "name": "Commissioner Control", + "code": 1873, + "mfgCode": null, + "define": "COMMISSIONER_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "RequestCommissioningApproval", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissionNode", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ReverseOpenCommissioningWindow", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedDeviceCategories", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "SupportedDeviceCategoryBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "CommissioningRequestResult", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] } ] }, diff --git a/src/app/clusters/commissioner-control-server/commissioner-control-server.cpp b/src/app/clusters/commissioner-control-server/commissioner-control-server.cpp new file mode 100644 index 00000000000000..98616f9e0e281b --- /dev/null +++ b/src/app/clusters/commissioner-control-server/commissioner-control-server.cpp @@ -0,0 +1,268 @@ +/* + * + * 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 "commissioner-control-server.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::app; + +using chip::Protocols::InteractionModel::Status; + +namespace { + +NodeId GetNodeId(const CommandHandler * commandObj) +{ + auto descriptor = commandObj->GetSubjectDescriptor(); + + if (descriptor.authMode != Access::AuthMode::kCase) + { + return kUndefinedNodeId; + } + return descriptor.subject; +} + +void AddReverseOpenCommissioningWindowResponse(CommandHandler * commandObj, const ConcreteCommandPath & path, + const Clusters::CommissionerControl::CommissioningWindowParams & params) +{ + Clusters::CommissionerControl::Commands::ReverseOpenCommissioningWindow::Type response; + response.commissioningTimeout = params.commissioningTimeout; + response.discriminator = params.discriminator; + response.iterations = params.iterations; + response.PAKEPasscodeVerifier = params.PAKEPasscodeVerifier; + response.salt = params.salt; + + commandObj->AddResponse(path, response); +} + +void RunDeferredCommissionNode(intptr_t commandArg) +{ + auto * info = reinterpret_cast(commandArg); + + Clusters::CommissionerControl::Delegate * delegate = + Clusters::CommissionerControl::CommissionerControlServer::Instance().GetDelegate(); + + if (delegate != nullptr) + { + CHIP_ERROR err = delegate->ReverseCommissionNode(info->params, info->ipAddress.GetIPAddress(), info->port); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "ReverseCommissionNode error: %" CHIP_ERROR_FORMAT, err.Format()); + } + } + else + { + ChipLogError(Zcl, "No delegate available for ReverseCommissionNode"); + } + + delete info; +} + +} // namespace + +namespace chip { +namespace app { +namespace Clusters { +namespace CommissionerControl { + +CommissionerControlServer CommissionerControlServer::sInstance; + +CommissionerControlServer & CommissionerControlServer::Instance() +{ + return sInstance; +} + +CHIP_ERROR CommissionerControlServer::Init(Delegate & delegate) +{ + mDelegate = &delegate; + return CHIP_NO_ERROR; +} + +Status CommissionerControlServer::GetSupportedDeviceCategoriesValue( + EndpointId endpoint, BitMask * supportedDeviceCategories) const +{ + Status status = Attributes::SupportedDeviceCategories::Get(endpoint, supportedDeviceCategories); + if (status != Status::Success) + { + ChipLogProgress(Zcl, "CommissionerControl: reading supportedDeviceCategories, err:0x%x", to_underlying(status)); + } + return status; +} + +Status +CommissionerControlServer::SetSupportedDeviceCategoriesValue(EndpointId endpoint, + const BitMask supportedDeviceCategories) +{ + Status status = Status::Success; + + if ((status = Attributes::SupportedDeviceCategories::Set(endpoint, supportedDeviceCategories)) != Status::Success) + { + ChipLogProgress(Zcl, "CommissionerControl: writing supportedDeviceCategories, err:0x%x", to_underlying(status)); + return status; + } + + return status; +} + +CHIP_ERROR +CommissionerControlServer::GenerateCommissioningRequestResultEvent(const Events::CommissioningRequestResult::Type & result) +{ + EventNumber eventNumber; + CHIP_ERROR error = LogEvent(result, kRootEndpointId, eventNumber); + if (CHIP_NO_ERROR != error) + { + ChipLogError(Zcl, "CommissionerControl: Unable to emit CommissioningRequestResult event: %" CHIP_ERROR_FORMAT, + error.Format()); + } + + return error; +} + +} // namespace CommissionerControl +} // namespace Clusters +} // namespace app +} // namespace chip + +bool emberAfCommissionerControlClusterRequestCommissioningApprovalCallback( + app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, + const Clusters::CommissionerControl::Commands::RequestCommissioningApproval::DecodableType & commandData) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + Status status = Status::Success; + + ChipLogProgress(Zcl, "Received command to request commissioning approval"); + + auto sourceNodeId = GetNodeId(commandObj); + + // Check if the command is executed via a CASE session + if (sourceNodeId == kUndefinedNodeId) + { + ChipLogError(Zcl, "Commissioning approval request not executed via CASE session, failing with UNSUPPORTED_ACCESS"); + commandObj->AddStatus(commandPath, Status::UnsupportedAccess); + return true; + } + + auto fabricIndex = commandObj->GetAccessingFabricIndex(); + auto requestId = commandData.requestId; + auto vendorId = commandData.vendorId; + auto productId = commandData.productId; + + // The label assigned from commandData need to be stored in CommissionerControl::Delegate which ensure that the backing buffer + // of it has a valid lifespan during fabric sync setup process. + auto & label = commandData.label; + + // Create a CommissioningApprovalRequest struct and populate it with the command data + Clusters::CommissionerControl::CommissioningApprovalRequest request = { .requestId = requestId, + .vendorId = vendorId, + .productId = productId, + .clientNodeId = sourceNodeId, + .fabricIndex = fabricIndex, + .label = label }; + + Clusters::CommissionerControl::Delegate * delegate = + Clusters::CommissionerControl::CommissionerControlServer::Instance().GetDelegate(); + + VerifyOrExit(delegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + // Handle commissioning approval request + err = delegate->HandleCommissioningApprovalRequest(request); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "emberAfCommissionerControlClusterRequestCommissioningApprovalCallback error: %" CHIP_ERROR_FORMAT, + err.Format()); + status = StatusIB(err).mStatus; + } + + commandObj->AddStatus(commandPath, status); + return true; +} + +bool emberAfCommissionerControlClusterCommissionNodeCallback( + app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, + const Clusters::CommissionerControl::Commands::CommissionNode::DecodableType & commandData) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + ChipLogProgress(Zcl, "Received command to commission node"); + + auto sourceNodeId = GetNodeId(commandObj); + + // Check if the command is executed via a CASE session + if (sourceNodeId == kUndefinedNodeId) + { + ChipLogError(Zcl, "Commission node request not executed via CASE session, failing with UNSUPPORTED_ACCESS"); + commandObj->AddStatus(commandPath, Status::UnsupportedAccess); + return true; + } + + auto requestId = commandData.requestId; + + auto commissionNodeInfo = std::make_unique(); + + Clusters::CommissionerControl::Delegate * delegate = + Clusters::CommissionerControl::CommissionerControlServer::Instance().GetDelegate(); + + VerifyOrExit(delegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + // Set IP address and port in the CommissionNodeInfo struct + commissionNodeInfo->port = commandData.port; + err = commissionNodeInfo->ipAddress.SetIPAddress(commandData.ipAddress); + SuccessOrExit(err == CHIP_NO_ERROR); + + // Validate the commission node command. + err = delegate->ValidateCommissionNodeCommand(sourceNodeId, requestId); + SuccessOrExit(err == CHIP_NO_ERROR); + + // Populate the parameters for the commissioning window + err = delegate->GetCommissioningWindowParams(commissionNodeInfo->params); + SuccessOrExit(err == CHIP_NO_ERROR); + + // Add the response for the commissioning window. + AddReverseOpenCommissioningWindowResponse(commandObj, commandPath, commissionNodeInfo->params); + + // Schedule the deferred reverse commission node task + DeviceLayer::PlatformMgr().ScheduleWork(RunDeferredCommissionNode, reinterpret_cast(commissionNodeInfo.release())); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "emberAfCommissionerControlClusterCommissionNodeCallback error: %" CHIP_ERROR_FORMAT, err.Format()); + commandObj->AddStatus(commandPath, StatusIB(err).mStatus); + } + + return true; +} + +void MatterCommissionerControlPluginServerInitCallback() +{ + ChipLogProgress(Zcl, "Initializing Commissioner Control cluster."); +} diff --git a/src/app/clusters/commissioner-control-server/commissioner-control-server.h b/src/app/clusters/commissioner-control-server/commissioner-control-server.h new file mode 100644 index 00000000000000..5e2422f5ebe018 --- /dev/null +++ b/src/app/clusters/commissioner-control-server/commissioner-control-server.h @@ -0,0 +1,182 @@ +/* + * + * 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. + */ +#pragma once + +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace CommissionerControl { + +// Spec indicates that IP Address is either 4 or 16 bytes. +static constexpr size_t kIpAddressBufferSize = 16; + +struct CommissioningApprovalRequest +{ + uint64_t requestId; + VendorId vendorId; + uint16_t productId; + NodeId clientNodeId; + FabricIndex fabricIndex; + Optional label; +}; + +struct CommissioningWindowParams +{ + uint32_t iterations; + uint16_t commissioningTimeout; + uint16_t discriminator; + ByteSpan PAKEPasscodeVerifier; + ByteSpan salt; +}; + +class ProtectedIPAddress +{ +public: + const Optional GetIPAddress() { return ipAddress; } + + CHIP_ERROR SetIPAddress(const Optional & address) + { + if (!address.HasValue()) + { + ipAddress.ClearValue(); + return CHIP_NO_ERROR; + } + + const ByteSpan & addressSpan = address.Value(); + size_t addressLength = addressSpan.size(); + if (addressLength != 4 && addressLength != 16) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + memcpy(ipAddressBuffer, addressSpan.data(), addressLength); + ipAddress.SetValue(ByteSpan(ipAddressBuffer, addressLength)); + return CHIP_NO_ERROR; + } + +private: + Optional ipAddress; + uint8_t ipAddressBuffer[kIpAddressBufferSize]; +}; + +struct CommissionNodeInfo +{ + CommissioningWindowParams params; + ProtectedIPAddress ipAddress; + Optional port; +}; + +class Delegate +{ +public: + /** + * @brief Handle a commissioning approval request. + * + * This command is sent by a client to request approval for a future CommissionNode call. + * The server SHALL always return SUCCESS to a correctly formatted RequestCommissioningApproval + * command, and then send a CommissioningRequestResult event once the result is ready. + * + * @param request The commissioning approval request to handle. + * @return CHIP_ERROR indicating the success or failure of the operation. + */ + virtual CHIP_ERROR HandleCommissioningApprovalRequest(const CommissioningApprovalRequest & request) = 0; + + /** + * @brief Validate a commission node command. + * + * This command is sent by a client to request that the server begins commissioning a previously + * approved request. + * + * The server SHALL return FAILURE if the CommissionNode command is not sent from the same + * NodeId as the RequestCommissioningApproval or if the provided RequestId to CommissionNode + * does not match the value provided to RequestCommissioningApproval. + * + * The validation SHALL fail if the client Node ID is kUndefinedNodeId, such as getting the NodeID from + * a group or PASE session. + * + * @param clientNodeId The NodeId of the client. + * @param requestId The request ID to validate. + * @return CHIP_ERROR indicating the success or failure of the operation. + */ + virtual CHIP_ERROR ValidateCommissionNodeCommand(NodeId clientNodeId, uint64_t requestId) = 0; + + /** + * @brief Get the parameters for the commissioning window. + * + * This method is called to retrieve the parameters needed for the commissioning window. + * + * @param[out] outParams The parameters for the commissioning window. + * @return CHIP_ERROR indicating the success or failure of the operation. + */ + virtual CHIP_ERROR GetCommissioningWindowParams(CommissioningWindowParams & outParams) = 0; + + /** + * @brief Reverse the commission node process. + * + * When received within the timeout specified by CommissionNode, the client SHALL open a + * commissioning window on the node which the client called RequestCommissioningApproval to + * have commissioned. + * + * @param params The parameters for the commissioning window. + * @param ipAddress Optional IP address for the commissioning window. + * @param port Optional port for the commissioning window. + * @return CHIP_ERROR indicating the success or failure of the operation. + */ + virtual CHIP_ERROR ReverseCommissionNode(const CommissioningWindowParams & params, const Optional & ipAddress, + const Optional & port) = 0; + + virtual ~Delegate() = default; +}; + +class CommissionerControlServer +{ +public: + static CommissionerControlServer & Instance(); + + CHIP_ERROR Init(Delegate & delegate); + + Delegate * GetDelegate() { return mDelegate; } + + Protocols::InteractionModel::Status + GetSupportedDeviceCategoriesValue(EndpointId endpoint, + BitMask * supportedDeviceCategories) const; + + Protocols::InteractionModel::Status + SetSupportedDeviceCategoriesValue(EndpointId endpoint, const BitMask supportedDeviceCategories); + + /** + * @brief + * Called after the server return SUCCESS to a correctly formatted RequestCommissioningApproval command. + */ + CHIP_ERROR GenerateCommissioningRequestResultEvent(const Events::CommissioningRequestResult::Type & result); + +private: + CommissionerControlServer() = default; + ~CommissionerControlServer() = default; + + static CommissionerControlServer sInstance; + + Delegate * mDelegate = nullptr; +}; + +} // namespace CommissionerControl +} // namespace Clusters +} // namespace app +} // namespace chip From 6180583d70cb1728109ef5d1ec855d42e1124f1f Mon Sep 17 00:00:00 2001 From: cdj <45139296+DejinChen@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:41:05 +0800 Subject: [PATCH 17/17] Added python testing for secondary network interface (#34307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added python testing for secondary network interface * Restyled by autopep8 * Restyled by isort * Modified test steps * Use NumNetworkCommissioning in test * Fix CI error. * Update src/python_testing/TC_CNET_1_4.py Co-authored-by: René Josefsen <69624991+ReneJosefsen@users.noreply.github.com> * Update src/python_testing/TC_CNET_1_4.py Co-authored-by: René Josefsen <69624991+ReneJosefsen@users.noreply.github.com> * check response instead of reading on endpoint 0 * modified step description * Modified step description. * Update steps. * Update steps. --------- Co-authored-by: Restyled.io Co-authored-by: René Josefsen <69624991+ReneJosefsen@users.noreply.github.com> --- .github/workflows/tests.yaml | 1 + src/python_testing/TC_CNET_1_4.py | 106 ++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/python_testing/TC_CNET_1_4.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 554ee752ff2a08..592227758c035e 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -503,6 +503,7 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_5.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_AccessChecker.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CGEN_2_4.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CNET_1_4.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DA_1_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DA_1_5.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DA_1_7.py' diff --git a/src/python_testing/TC_CNET_1_4.py b/src/python_testing/TC_CNET_1_4.py new file mode 100644 index 00000000000000..d7560c4fd03942 --- /dev/null +++ b/src/python_testing/TC_CNET_1_4.py @@ -0,0 +1,106 @@ +# +# 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. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +import logging + +import chip.clusters as Clusters +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + +kRootEndpointId = 0 +kSecondaryNetworkInterfaceDeviceTypeId = 0x0019 + + +class TC_CNET_1_4(MatterBaseTest): + def steps_TC_CNET_1_4(self): + return [TestStep(1, "TH is commissioned", is_commissioning=True), + TestStep(2, 'TH performs a wildcard read of the FeatureMap attribute on Network Commissioning clusters across all endpoints, and saves the response as `NetworkCommissioningResponse`'), + TestStep(3, 'If `NetworkCommissioningResponse` does not contain any entries for Network Commissioning cluster, skip remaining steps and end test case'), + TestStep(4, 'If `NetworkCommissioningResponse` contains only a single entry for Network Commissioning cluster on Endpoint 0, skip remaining steps and end test case. Verify `NetworkCommissioningResponse` contains an entry for Network Commissioning cluster on Endpoint 0'), + TestStep(5, 'TH reads from the DUT the Descriptor Cluster DeviceTypeList attribute on each endpoint from the `NetworkCommissioningResponse` (except for Endpoint 0), verify that the Secondary Network Interface device type id (0x0019) is listed in the DeviceTypeList'), + TestStep(6, 'TH reads from the DUT the General Commissioning Cluster SupportsConcurrentConnection attribute, verify that it is true')] + + def def_TC_CNET_1_4(self): + return '[TC-CNET-1.4] Verification for Secondary Network Interface [DUT-Server]' + + def pics_TC_CNET_1_4(self): + return ['CNET.S'] + + # Override default timeout. + @property + def default_timeout(self) -> int: + return 200 + + @async_test_body + async def test_TC_CNET_1_4(self): + # Commissioning is already done + self.step(1) + + self.step(2) + # Read FeatureMap attribute with wildcard endpoint + NetworkCommissioningResponse = await self.default_controller.ReadAttribute(self.dut_node_id, [(Clusters.NetworkCommissioning.Attributes.FeatureMap)], fabricFiltered=True) + + self.step(3) + NumNetworkCommissioning = len(NetworkCommissioningResponse) + if NumNetworkCommissioning == 0: + logging.info('No endpoint has Network Commissioning Cluster, skipping remaining steps') + self.skip_all_remaining_steps(4) + return + + self.step(4) + endpoints = [] + for endpoint, _ in NetworkCommissioningResponse.items(): + endpoints.append(endpoint) + if kRootEndpointId not in endpoints: + asserts.assert_true(False, "There is no Network Commissioning Cluster on endpoint 0") + + if NumNetworkCommissioning == 1: + logging.info('Only endpoint 0 has Network Commissioning Cluster, skipping remaining steps') + self.skip_all_remaining_steps(5) + return + + self.step(5) + for endpoint in endpoints: + if endpoint == kRootEndpointId: + continue + device_type_list = await self.read_single_attribute_check_success(cluster=Clusters.Descriptor, + attribute=Clusters.Descriptor.Attributes.DeviceTypeList, endpoint=endpoint) + required_device_types = {kSecondaryNetworkInterfaceDeviceTypeId} + found_device_types = {device.deviceType for device in device_type_list} + asserts.assert_true(required_device_types.intersection(found_device_types), + "Network Commissioning Cluster is not on Root Node or Secondary Network Interface") + + self.step(6) + concurrent_connection = await self.read_single_attribute_check_success(cluster=Clusters.GeneralCommissioning, + attribute=Clusters.GeneralCommissioning.Attributes.SupportsConcurrentConnection) + asserts.assert_true(concurrent_connection, "The device does not support concurrent connection commissioning") + + +if __name__ == "__main__": + default_matter_test_main()