From 80accab3aa20a1689acd4fcc20556570baf75bb9 Mon Sep 17 00:00:00 2001 From: chulspro Date: Thu, 20 Jul 2023 14:33:35 +0900 Subject: [PATCH] [Android] Add Android Matter Device App for automation testing (#27799) --- docs/examples/index.md | 9 + examples/virtual-device-app/android/.gn | 25 + .../virtual-device-app/android/App/.gitignore | 26 + .../android/App/app/.gitignore | 1 + .../android/App/app/build.gradle.kts | 98 + .../android/App/app/proguard-rules.pro | 21 + .../device/app/ExampleInstrumentedTest.kt | 22 + .../App/app/src/main/AndroidManifest.xml | 31 + .../app/src/main/ic_launcher-playstore.png | Bin 0 -> 41296 bytes .../java/com/matter/virtual/device/app/App.kt | 14 + .../matter/virtual/device/app/MainActivity.kt | 67 + .../virtual/device/app/TimberDebugTree.kt | 13 + .../res/drawable/ic_launcher_background.xml | 74 + .../res/drawable/ic_launcher_foreground.xml | 31 + .../app/src/main/res/layout/activity_main.xml | 30 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3735 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5523 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2689 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3472 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5164 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7893 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 8263 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 12604 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 11238 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 17524 bytes .../app/src/main/res/navigation/nav_graph.xml | 10 + .../app/src/main/res/values-night/colors.xml | 5 + .../App/app/src/main/res/values/strings.xml | 3 + .../virtual/device/app/ExampleUnitTest.kt | 16 + .../android/App/build.gradle.kts | 25 + .../android/App/buildSrc/.gitignore | 0 .../android/App/buildSrc/build.gradle.kts | 7 + .../src/main/java/com/matter/buildsrc/Deps.kt | 49 + .../main/java/com/matter/buildsrc/Versions.kt | 8 + .../android/App/core/common/.gitignore | 0 .../android/App/core/common/build.gradle.kts | 60 + .../App/core/common/proguard-rules.pro | 21 + .../core/common/ExampleInstrumentedTest.kt | 22 + .../core/common/src/main/AndroidManifest.xml | 4 + .../device/app/core/common/DeepLink.kt | 21 + .../virtual/device/app/core/common/Device.kt | 38 + .../device/app/core/common/MatterConstants.kt | 11 + .../device/app/core/common/MatterSettings.kt | 11 + .../device/app/core/common/QrcodeUtil.kt | 29 + .../virtual/device/app/core/common/Result.kt | 20 + .../app/core/common/di/CoroutinesModule.kt | 30 + .../core/common/di/CoroutinesQualifiers.kt | 11 + .../common/ui/DisableAppBarLayoutBehavior.kt | 31 + .../src/main/res/drawable/menu_item_bg.xml | 6 + .../res/drawable/round_device_unknown_24.xml | 5 + .../main/res/drawable/round_toggle_on_24.xml | 5 + .../src/main/res/values-night/colors.xml | 5 + .../common/src/main/res/values/colors.xml | 12 + .../common/src/main/res/values/dimens.xml | 25 + .../common/src/main/res/values/strings.xml | 6 + .../common/src/main/res/values/themes.xml | 27 + .../device/app/core/common/ExampleUnitTest.kt | 16 + .../android/App/core/data/.gitignore | 0 .../android/App/core/data/build.gradle.kts | 55 + .../android/App/core/data/proguard-rules.pro | 21 + .../app/core/data/ExampleInstrumentedTest.kt | 22 + .../core/data/src/main/AndroidManifest.xml | 4 + .../device/app/core/data/di/DataModule.kt | 19 + .../core/data/repository/MatterRepository.kt | 9 + .../data/repository/MatterRepositoryImpl.kt | 17 + .../core/data/repository/NetworkRepository.kt | 5 + .../data/repository/NetworkRepositoryImpl.kt | 34 + .../device/app/core/data/ExampleUnitTest.kt | 16 + .../android/App/core/domain/.gitignore | 0 .../android/App/core/domain/build.gradle.kts | 52 + .../App/core/domain/proguard-rules.pro | 21 + .../core/domain/ExampleInstrumentedTest.kt | 22 + .../core/domain/src/main/AndroidManifest.xml | 4 + .../app/core/domain/CoroutineUseCase.kt | 18 + .../core/domain/NonParamCoroutineUseCase.kt | 18 + .../GetManualPairingCodeStringUseCase.kt | 20 + .../usecase/matter/GetQrCodeStringUseCase.kt | 20 + .../domain/usecase/network/GetSSIDUseCase.kt | 19 + .../device/app/core/domain/ExampleUnitTest.kt | 16 + .../android/App/core/matter/.gitignore | 0 .../android/App/core/matter/build.gradle.kts | 60 + .../App/core/matter/proguard-rules.pro | 21 + .../core/matter/ExampleInstrumentedTest.kt | 22 + .../core/matter/src/main/AndroidManifest.xml | 4 + .../device/app/core/matter/MatterApi.kt | 40 + .../device/app/core/matter/model/Payload.kt | 33 + .../device/app/core/matter/ExampleUnitTest.kt | 16 + .../android/App/core/model/.gitignore | 0 .../android/App/core/model/build.gradle.kts | 44 + .../android/App/core/model/proguard-rules.pro | 21 + .../app/core/model/ExampleInstrumentedTest.kt | 22 + .../core/model/src/main/AndroidManifest.xml | 4 + .../device/app/core/model/OnobardingType.kt | 16 + .../virtual/device/app/core/model/Payload.kt | 3 + .../device/app/core/model/ExampleUnitTest.kt | 16 + .../android/App/feature/main/.gitignore | 0 .../android/App/feature/main/build.gradle.kts | 69 + .../App/feature/main/proguard-rules.pro | 21 + .../feature/main/ExampleInstrumentedTest.kt | 22 + .../feature/main/src/main/AndroidManifest.xml | 4 + .../device/app/feature/main/BindingAdapter.kt | 13 + .../device/app/feature/main/MainFragment.kt | 122 + .../device/app/feature/main/MenuAdapter.kt | 46 + .../main/VerticalSpaceItemDecoration.kt | 25 + .../device/app/feature/main/model/Menu.kt | 19 + .../src/main/res/layout/fragment_main.xml | 104 + .../main/src/main/res/layout/item_menu.xml | 61 + .../main/res/navigation/main_nav_graph.xml | 13 + .../main/src/main/res/values/strings.xml | 4 + .../app/feature/main/ExampleUnitTest.kt | 16 + .../android/App/feature/qrcode/.gitignore | 0 .../App/feature/qrcode/build.gradle.kts | 69 + .../App/feature/qrcode/proguard-rules.pro | 21 + .../feature/qrcode/ExampleInstrumentedTest.kt | 22 + .../qrcode/src/main/AndroidManifest.xml | 4 + .../app/feature/qrcode/QrcodeFragment.kt | 159 + .../app/feature/qrcode/QrcodeViewModel.kt | 65 + .../src/main/res/layout/fragment_qrcode.xml | 258 + .../main/res/navigation/qrcode_nav_graph.xml | 18 + .../qrcode/src/main/res/values/strings.xml | 13 + .../app/feature/qrcode/ExampleUnitTest.kt | 16 + .../android/App/feature/setup/.gitignore | 0 .../App/feature/setup/build.gradle.kts | 69 + .../App/feature/setup/proguard-rules.pro | 21 + .../feature/setup/ExampleInstrumentedTest.kt | 22 + .../setup/src/main/AndroidManifest.xml | 4 + .../device/app/feature/setup/SetupFragment.kt | 172 + .../app/feature/setup/SetupViewModel.kt | 27 + .../setup/src/main/res/drawable/dialog_bg.xml | 9 + .../round_notification_important_24.xml | 5 + .../main/res/layout/dialog_setup_continue.xml | 138 + .../src/main/res/layout/fragment_setup.xml | 291 + .../main/res/navigation/setup_nav_graph.xml | 18 + .../setup/src/main/res/values-ko/strings.xml | 8 + .../src/main/res/values-night/colors.xml | 5 + .../setup/src/main/res/values/colors.xml | 6 + .../setup/src/main/res/values/strings.xml | 18 + .../app/feature/setup/ExampleUnitTest.kt | 16 + .../android/App/gradle.properties | 28 + .../App/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../virtual-device-app/android/App/gradlew | 184 + .../android/App/gradlew.bat | 89 + .../android/App/settings.gradle.kts | 24 + examples/virtual-device-app/android/BUILD.gn | 92 + examples/virtual-device-app/android/README.md | 63 + examples/virtual-device-app/android/args.gni | 27 + .../android/build_overrides | 1 + .../android/java/AppImpl.cpp | 103 + .../virtual-device-app/android/java/AppImpl.h | 23 + .../android/java/ClusterChangeAttribute.cpp | 56 + .../android/java/DeviceApp-JNI.cpp | 159 + .../android/java/DeviceApp-JNI.h | 42 + .../android/java/JNIDACProvider.cpp | 172 + .../android/java/JNIDACProvider.h | 43 + .../android/java/OnOffManager.cpp | 128 + .../android/java/OnOffManager.h | 45 + .../virtual/device/app/DACProvider.java | 32 + .../matter/virtual/device/app/DeviceApp.java | 62 + .../virtual/device/app/DeviceAppCallback.java | 23 + .../virtual/device/app/OnOffManager.java | 11 + .../android/third_party/connectedhomeip | 1 + .../virtual-device-common/BUILD.gn | 26 + .../include/CHIPProjectAppConfig.h | 52 + .../virtual-device-app.matter | 1925 ++ .../virtual-device-app.zap | 15641 ++++++++++++++++ scripts/build/build/targets.py | 2 + scripts/build/builders/android.py | 37 + .../build/testdata/all_targets_linux_x64.txt | 2 +- 171 files changed, 22857 insertions(+), 1 deletion(-) create mode 100644 examples/virtual-device-app/android/.gn create mode 100644 examples/virtual-device-app/android/App/.gitignore create mode 100644 examples/virtual-device-app/android/App/app/.gitignore create mode 100644 examples/virtual-device-app/android/App/app/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/app/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/app/src/androidTest/java/com/matter/virtual/device/app/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/ic_launcher-playstore.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/App.kt create mode 100644 examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt create mode 100644 examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/TimberDebugTree.kt create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/layout/activity_main.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/navigation/nav_graph.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/values-night/colors.xml create mode 100644 examples/virtual-device-app/android/App/app/src/main/res/values/strings.xml create mode 100644 examples/virtual-device-app/android/App/app/src/test/java/com/matter/virtual/device/app/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/buildSrc/.gitignore create mode 100644 examples/virtual-device-app/android/App/buildSrc/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Deps.kt create mode 100644 examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Versions.kt create mode 100644 examples/virtual-device-app/android/App/core/common/.gitignore create mode 100644 examples/virtual-device-app/android/App/core/common/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/core/common/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/core/common/src/androidTest/java/com/matter/virtual/device/app/core/common/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Device.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterSettings.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/QrcodeUtil.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Result.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesModule.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesQualifiers.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/drawable/menu_item_bg.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_device_unknown_24.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_toggle_on_24.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/values-night/colors.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/values/colors.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/values/strings.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/res/values/themes.xml create mode 100644 examples/virtual-device-app/android/App/core/common/src/test/java/com/matter/virtual/device/app/core/common/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/core/data/.gitignore create mode 100644 examples/virtual-device-app/android/App/core/data/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/core/data/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/core/data/src/androidTest/java/com/matter/virtual/device/app/core/data/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepository.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepositoryImpl.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/test/java/com/matter/virtual/device/app/core/data/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/.gitignore create mode 100644 examples/virtual-device-app/android/App/core/domain/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/core/domain/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/core/domain/src/androidTest/java/com/matter/virtual/device/app/core/domain/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/CoroutineUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/NonParamCoroutineUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetManualPairingCodeStringUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetQrCodeStringUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/network/GetSSIDUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/test/java/com/matter/virtual/device/app/core/domain/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/core/matter/.gitignore create mode 100644 examples/virtual-device-app/android/App/core/matter/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/core/matter/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/core/matter/src/androidTest/java/com/matter/virtual/device/app/core/matter/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApi.kt create mode 100644 examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/model/Payload.kt create mode 100644 examples/virtual-device-app/android/App/core/matter/src/test/java/com/matter/virtual/device/app/core/matter/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/core/model/.gitignore create mode 100644 examples/virtual-device-app/android/App/core/model/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/core/model/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/core/model/src/androidTest/java/com/matter/virtual/device/app/core/model/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/core/model/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/OnobardingType.kt create mode 100644 examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/Payload.kt create mode 100644 examples/virtual-device-app/android/App/core/model/src/test/java/com/matter/virtual/device/app/core/model/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/.gitignore create mode 100644 examples/virtual-device-app/android/App/feature/main/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/feature/main/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/feature/main/src/androidTest/java/com/matter/virtual/device/app/feature/main/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/BindingAdapter.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MenuAdapter.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/VerticalSpaceItemDecoration.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/model/Menu.kt create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_main.xml create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/res/layout/item_menu.xml create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/res/navigation/main_nav_graph.xml create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml create mode 100644 examples/virtual-device-app/android/App/feature/main/src/test/java/com/matter/virtual/device/app/feature/main/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/.gitignore create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/androidTest/java/com/matter/virtual/device/app/feature/qrcode/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeFragment.kt create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/main/res/navigation/qrcode_nav_graph.xml create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/main/res/values/strings.xml create mode 100644 examples/virtual-device-app/android/App/feature/qrcode/src/test/java/com/matter/virtual/device/app/feature/qrcode/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/feature/setup/.gitignore create mode 100644 examples/virtual-device-app/android/App/feature/setup/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/feature/setup/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/androidTest/java/com/matter/virtual/device/app/feature/setup/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupFragment.kt create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupViewModel.kt create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/dialog_bg.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/round_notification_important_24.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/dialog_setup_continue.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/fragment_setup.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/navigation/setup_nav_graph.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/values-ko/strings.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/values-night/colors.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/values/colors.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/main/res/values/strings.xml create mode 100644 examples/virtual-device-app/android/App/feature/setup/src/test/java/com/matter/virtual/device/app/feature/setup/ExampleUnitTest.kt create mode 100644 examples/virtual-device-app/android/App/gradle.properties create mode 100755 examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/virtual-device-app/android/App/gradlew create mode 100644 examples/virtual-device-app/android/App/gradlew.bat create mode 100644 examples/virtual-device-app/android/App/settings.gradle.kts create mode 100644 examples/virtual-device-app/android/BUILD.gn create mode 100644 examples/virtual-device-app/android/README.md create mode 100644 examples/virtual-device-app/android/args.gni create mode 120000 examples/virtual-device-app/android/build_overrides create mode 100644 examples/virtual-device-app/android/java/AppImpl.cpp create mode 100644 examples/virtual-device-app/android/java/AppImpl.h create mode 100644 examples/virtual-device-app/android/java/ClusterChangeAttribute.cpp create mode 100644 examples/virtual-device-app/android/java/DeviceApp-JNI.cpp create mode 100644 examples/virtual-device-app/android/java/DeviceApp-JNI.h create mode 100644 examples/virtual-device-app/android/java/JNIDACProvider.cpp create mode 100644 examples/virtual-device-app/android/java/JNIDACProvider.h create mode 100644 examples/virtual-device-app/android/java/OnOffManager.cpp create mode 100644 examples/virtual-device-app/android/java/OnOffManager.h create mode 100644 examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DACProvider.java create mode 100644 examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java create mode 100644 examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java create mode 100644 examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java create mode 120000 examples/virtual-device-app/android/third_party/connectedhomeip create mode 100644 examples/virtual-device-app/virtual-device-common/BUILD.gn create mode 100644 examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h create mode 100644 examples/virtual-device-app/virtual-device-common/virtual-device-app.matter create mode 100644 examples/virtual-device-app/virtual-device-common/virtual-device-app.zap diff --git a/docs/examples/index.md b/docs/examples/index.md index 0ecda80b9d6a6b..e7b6224bdda1a1 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -78,6 +78,15 @@ darwin-framework-tool/README java-matter-controller/README ``` +## Virtual Device App example + +```{toctree} +:glob: +:maxdepth: 1 + +virtual-device-app/**/README +``` + ## Lighting example ```{toctree} diff --git a/examples/virtual-device-app/android/.gn b/examples/virtual-device-app/android/.gn new file mode 100644 index 00000000000000..747b125d35d3c2 --- /dev/null +++ b/examples/virtual-device-app/android/.gn @@ -0,0 +1,25 @@ +# 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. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + import("//args.gni") +} diff --git a/examples/virtual-device-app/android/App/.gitignore b/examples/virtual-device-app/android/App/.gitignore new file mode 100644 index 00000000000000..c9ad62ce32cf40 --- /dev/null +++ b/examples/virtual-device-app/android/App/.gitignore @@ -0,0 +1,26 @@ +*.iml +.gradle +/local.properties +/.idea/misc.xml +/.idea/gradle.xml +/.idea/compiler.xml +/.idea/.name +/.idea/jarRepositories.xml +/.idea/vcs.xml +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.idea/** +.DS_Store +/captures +.externalNativeBuild +.cxx +local.properties + +# Shared libs & JAR libs (those libs are copied into source tree for easy Android build). +*.so +*.jar +*.map diff --git a/examples/virtual-device-app/android/App/app/.gitignore b/examples/virtual-device-app/android/App/app/.gitignore new file mode 100644 index 00000000000000..757fee31c9045c --- /dev/null +++ b/examples/virtual-device-app/android/App/app/.gitignore @@ -0,0 +1 @@ +/.idea \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/build.gradle.kts b/examples/virtual-device-app/android/App/app/build.gradle.kts new file mode 100644 index 00000000000000..3b139f2b61b6ad --- /dev/null +++ b/examples/virtual-device-app/android/App/app/build.gradle.kts @@ -0,0 +1,98 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.application") + id("kotlin-android") + id("dagger.hilt.android.plugin") + id("androidx.navigation.safeargs.kotlin") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app" + compileSdk = Versions.compileSdkVersion + buildToolsVersion = Versions.buildToolsVersion + + defaultConfig { + applicationId = "com.matter.virtual.device.app" + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + targets += listOf("default") + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + + debug { + packagingOptions { + jniLibs.keepDebugSymbols.add("**/*.so") + } + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + dataBinding = true + } + kapt { + correctErrorTypes = true + } + sourceSets { + getByName("main") { + jniLibs.setSrcDirs(listOf("libs/jniLibs")) + } + } + packagingOptions { + jniLibs.pickFirsts.add("**/*.so") + jniLibs.useLegacyPackaging = true + } +} + +dependencies { + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) + + implementation(project(":core:common")) + implementation(project(":core:data")) + implementation(project(":core:domain")) + implementation(project(":core:model")) + implementation(project(":feature:main")) + implementation(project(":feature:qrcode")) + implementation(project(":feature:setup")) + + implementation(Deps.AndroidX.core) + implementation(Deps.AndroidX.appcompat) + implementation(Deps.material) + + implementation(Deps.Navigation.fragment) + implementation(Deps.Navigation.ui) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/proguard-rules.pro b/examples/virtual-device-app/android/App/app/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/androidTest/java/com/matter/virtual/device/app/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/app/src/androidTest/java/com/matter/virtual/device/app/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..09ae8b5b5a2b5b --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/androidTest/java/com/matter/virtual/device/app/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a57ddde21a56eb --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/ic_launcher-playstore.png b/examples/virtual-device-app/android/App/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..55c35b139dc27c096f9d86f3989fb5bd5d40f8ab GIT binary patch literal 41296 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 + permissions.entries.forEach { Timber.d("${it.key}:${it.value}") } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Timber.d("onCreate()") + + val isPermissionsGranted = + permissions.all { + ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED + } + + if (!isPermissionsGranted) { + requestMultiplePermissions.launch(permissions) + } + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + } + + override fun onDestroy() { + super.onDestroy() + Timber.d("onDestroy()") + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + onBackPressed() + return true + } + } + + return super.onOptionsItemSelected(item) + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + Timber.d("RequestCode:$requestCode") + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + } +} diff --git a/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/TimberDebugTree.kt b/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/TimberDebugTree.kt new file mode 100644 index 00000000000000..a317af1372ed99 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/TimberDebugTree.kt @@ -0,0 +1,13 @@ +package com.matter.virtual.device.app + +import timber.log.Timber + +class TimberDebugTree : Timber.DebugTree() { + override fun createStackElementTag(element: StackTraceElement): String { + return if (BuildConfig.DEBUG) { + "[STD]:${element.fileName}:${element.lineNumber}#${element.methodName}" + } else { + "[STD]:${element.className}#${element.methodName}" + } + } +} diff --git a/examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_background.xml b/examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000000000..ca3826a46ce070 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_foreground.xml b/examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000000000..da1dcd94e9d5c2 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/res/layout/activity_main.xml b/examples/virtual-device-app/android/App/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000000000..fd08d47433063f --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000000000..bbd3e021239ce7 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000000000..bbd3e021239ce7 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..06c2ae63795569e977985bd8346bd76910e26af1 GIT binary patch literal 3735 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 literal 0 HcmV?d00001 diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf22d879af102b28225750f5eb65195f222a330 GIT binary patch literal 5523 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 V&|BPqXEOi*002ovPDHLkV1hS8Z3+MY literal 0 HcmV?d00001 diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..3caf60918eaae5bda79d365df43bea281c7f8fde GIT binary patch literal 2689 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 I0|fT}0FwykX8-^I literal 0 HcmV?d00001 diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..07249dac25656321c4c0e3ced1e8a035c3444d74 GIT binary patch literal 7893 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 literal 0 HcmV?d00001 diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b77f5764199f2a486a5afb907e49a9e17c61ae GIT binary patch literal 8263 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 literal 0 HcmV?d00001 diff --git a/examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/virtual-device-app/android/App/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..1e239a77f6dba0cb4ebcacc980715586e9ad0878 GIT binary patch literal 17524 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 + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/res/values-night/colors.xml b/examples/virtual-device-app/android/App/app/src/main/res/values-night/colors.xml new file mode 100644 index 00000000000000..088fde391464b9 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/values-night/colors.xml @@ -0,0 +1,5 @@ + + + @android:color/white + #010101 + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/app/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/app/src/main/res/values/strings.xml new file mode 100644 index 00000000000000..8194edb5a4edd8 --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Matter Virtual Device + diff --git a/examples/virtual-device-app/android/App/app/src/test/java/com/matter/virtual/device/app/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/app/src/test/java/com/matter/virtual/device/app/ExampleUnitTest.kt new file mode 100644 index 00000000000000..8de371c92f9f9b --- /dev/null +++ b/examples/virtual-device-app/android/App/app/src/test/java/com/matter/virtual/device/app/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/build.gradle.kts b/examples/virtual-device-app/android/App/build.gradle.kts new file mode 100644 index 00000000000000..03ba9c9b33c1e3 --- /dev/null +++ b/examples/virtual-device-app/android/App/build.gradle.kts @@ -0,0 +1,25 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + val kotlinVersion = "1.8.10" + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath("com.android.tools.build:gradle:7.3.1") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion") + classpath("com.google.dagger:hilt-android-gradle-plugin:2.44.2") + classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3") + } +} + +allprojects { + buildDir = File("${rootProject.buildDir}/${project.name}") +} + +tasks.register("clean", Delete::class) { + delete(rootProject.buildDir) +} diff --git a/examples/virtual-device-app/android/App/buildSrc/.gitignore b/examples/virtual-device-app/android/App/buildSrc/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/buildSrc/build.gradle.kts b/examples/virtual-device-app/android/App/buildSrc/build.gradle.kts new file mode 100644 index 00000000000000..b22ed732fde2c5 --- /dev/null +++ b/examples/virtual-device-app/android/App/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Deps.kt b/examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Deps.kt new file mode 100644 index 00000000000000..2593dca0ee3227 --- /dev/null +++ b/examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Deps.kt @@ -0,0 +1,49 @@ +package com.matter.buildsrc + +object Deps { + object AndroidX { + const val core = "androidx.core:core-ktx:1.8.0" + const val appcompat = "androidx.appcompat:appcompat:1.5.1" + const val fragment = "androidx.fragment:fragment-ktx:1.5.7" + + object Lifecycle { + private const val lifecycleVersion = "2.3.1" + const val viewmodel = "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" + const val livedata = "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" + const val compiler = "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion" + } + } + + const val material = "com.google.android.material:material:1.7.0" + + object Kotlin { + const val coroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0" + const val coroutinesAndroid = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1" + const val reflect = "org.jetbrains.kotlin:kotlin-reflect:1.5.31" + const val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2" + } + + object Dagger { + private const val daggerVersion = "2.44.2" + const val hiltAndroid = "com.google.dagger:hilt-android:$daggerVersion" + const val hiltAndroidCompiler = "com.google.dagger:hilt-android-compiler:$daggerVersion" + } + + object Test { + const val junit = "junit:junit:4.13.2" + const val junitExt = "androidx.test.ext:junit:1.1.3" + const val espresso = "androidx.test.espresso:espresso-core:3.4.0" + } + + object Navigation { + private const val navigationVersion = "2.5.3" + const val fragment = "androidx.navigation:navigation-fragment-ktx:$navigationVersion" + const val ui = "androidx.navigation:navigation-ui-ktx:$navigationVersion" + } + + const val timber = "com.jakewharton.timber:timber:5.0.1" + const val inject = "javax.inject:javax.inject:1" + const val zxing = "com.google.zxing:core:3.4.0" + const val lottie = "com.airbnb.android:lottie:3.4.1" + const val gson = "com.google.code.gson:gson:2.8.5" +} diff --git a/examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Versions.kt b/examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Versions.kt new file mode 100644 index 00000000000000..543ed231e3709c --- /dev/null +++ b/examples/virtual-device-app/android/App/buildSrc/src/main/java/com/matter/buildsrc/Versions.kt @@ -0,0 +1,8 @@ +package com.matter.buildsrc + +object Versions { + const val compileSdkVersion = 33 + const val buildToolsVersion = "31.0.0" + const val minSdkVersion = 24 + const val targetSdkVersion = 33 +} diff --git a/examples/virtual-device-app/android/App/core/common/.gitignore b/examples/virtual-device-app/android/App/core/common/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/core/common/build.gradle.kts b/examples/virtual-device-app/android/App/core/common/build.gradle.kts new file mode 100644 index 00000000000000..d424108ab919de --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/build.gradle.kts @@ -0,0 +1,60 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.serialization") + id("com.google.dagger.hilt.android") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.core.common" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation(project(":core:model")) + + implementation(Deps.Kotlin.serialization) + implementation(Deps.Kotlin.reflect) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.Navigation.fragment) + implementation(Deps.Navigation.ui) + + implementation(Deps.zxing) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/proguard-rules.pro b/examples/virtual-device-app/android/App/core/common/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/androidTest/java/com/matter/virtual/device/app/core/common/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/core/common/src/androidTest/java/com/matter/virtual/device/app/core/common/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..54876ab392e911 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/androidTest/java/com/matter/virtual/device/app/core/common/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.core.common + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.core.common.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/common/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt new file mode 100644 index 00000000000000..1a84f4a6840cd2 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt @@ -0,0 +1,21 @@ +package com.matter.virtual.device.app.core.common + +import androidx.core.net.toUri +import androidx.navigation.NavDeepLinkRequest + +object DeepLink { + fun getDeepLinkRequestForQrcodeFragment(setting: String): NavDeepLinkRequest { + return NavDeepLinkRequest.Builder.fromUri( + "android-app://com.matter.virtual.device.app.feature.qrcode/qrcodeFragment/${setting}" + .toUri() + ) + .build() + } + + fun getDeepLinkRequestForSetupFragment(setting: String): NavDeepLinkRequest { + return NavDeepLinkRequest.Builder.fromUri( + "android-app://com.matter.virtual.device.app.feature.setup/setupFragment/${setting}".toUri() + ) + .build() + } +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Device.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Device.kt new file mode 100644 index 00000000000000..067898bbd79d93 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Device.kt @@ -0,0 +1,38 @@ +package com.matter.virtual.device.app.core.common + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import kotlinx.serialization.Serializable + +@Serializable +sealed class Device( + val title: String, + @StringRes val deviceNameResId: Int, + @DrawableRes val deviceIconResId: Int, + val deviceTypeId: Long, + val discriminator: Int +) { + @Serializable + object OnOffSwitch : + Device( + "onoffswitch", + R.string.matter_on_off_switch, + R.drawable.round_toggle_on_24, + 0x0103, + 3841 + ) + + @Serializable + object Unknown : + Device("unknown", R.string.matter_device, R.drawable.round_device_unknown_24, 65535, 3840) + + companion object { + fun map(title: String): Device { + return Device::class + .sealedSubclasses + .firstOrNull { it.objectInstance?.title == title } + ?.objectInstance + ?: Unknown + } + } +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt new file mode 100644 index 00000000000000..84f26bfca81b68 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt @@ -0,0 +1,11 @@ +package com.matter.virtual.device.app.core.common + +object MatterConstants { + const val DEFAULT_VERSION = 0 + const val DEFAULT_VENDOR_ID = 0xFFF1 + const val DEFAULT_PRODUCT_ID = 0x8001 + const val DEFAULT_COMMISSIONING_FLOW = 0 + const val DEFAULT_SETUP_PINCODE = 20202021L + const val DEFAULT_DISCRIMINATOR = 3840 + const val DEFAULT_DEVICE_NAME = "Matter Device" +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterSettings.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterSettings.kt new file mode 100644 index 00000000000000..dfa2f9e7542a51 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterSettings.kt @@ -0,0 +1,11 @@ +package com.matter.virtual.device.app.core.common + +import com.matter.virtual.device.app.core.model.OnboardingType +import kotlinx.serialization.Serializable + +@Serializable +data class MatterSettings( + var device: Device = Device.Unknown, + var onboardingType: OnboardingType = OnboardingType.UNKNOWN, + var discriminator: Int = MatterConstants.DEFAULT_DISCRIMINATOR +) diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/QrcodeUtil.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/QrcodeUtil.kt new file mode 100644 index 00000000000000..35f82d94c5c9a8 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/QrcodeUtil.kt @@ -0,0 +1,29 @@ +package com.matter.virtual.device.app.core.common + +import android.graphics.Bitmap +import android.graphics.Color +import com.google.zxing.BarcodeFormat +import com.google.zxing.qrcode.QRCodeWriter + +object QrcodeUtil { + + fun createQrCodeBitmap(contents: String, width: Int, height: Int): Bitmap? { + try { + val bitMatrix = QRCodeWriter().encode(contents, BarcodeFormat.QR_CODE, width, height) + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + + for (y in 0 until bitMatrix.height) { + for (x in 0 until bitMatrix.width) { + if (bitMatrix.get(x, y)) { + bitmap.setPixel(x, y, Color.BLACK) + } + } + } + + return bitmap + } catch (e: Exception) { + e.printStackTrace() + return null + } + } +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Result.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Result.kt new file mode 100644 index 00000000000000..02330400bebc5b --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Result.kt @@ -0,0 +1,20 @@ +package com.matter.virtual.device.app.core.common + +sealed class Result { + + data class Success(val data: T) : Result() + + data class Error(val exception: Throwable) : Result() + + object Loading : Result() +} + +val Result<*>.succeeded + get() = this is Result.Success && data != null + +fun Result.successOr(fallback: T): T { + return (this as? Result.Success)?.data ?: fallback +} + +val Result.data: T? + get() = (this as? Result.Success)?.data diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesModule.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesModule.kt new file mode 100644 index 00000000000000..ec4974e0c5646f --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesModule.kt @@ -0,0 +1,30 @@ +package com.matter.virtual.device.app.core.common.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +@InstallIn(SingletonComponent::class) +@Module +internal object CoroutinesModule { + @DefaultDispatcher + @Provides + @Singleton + fun provideDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default + + @IoDispatcher @Provides @Singleton fun provideIoDispatcher(): CoroutineDispatcher = Dispatchers.IO + + @MainDispatcher + @Provides + @Singleton + fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main + + @MainImmediateDispatcher + @Provides + @Singleton + fun provideMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesQualifiers.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesQualifiers.kt new file mode 100644 index 00000000000000..ac55fb68756e17 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/di/CoroutinesQualifiers.kt @@ -0,0 +1,11 @@ +package com.matter.virtual.device.app.core.common.di + +import javax.inject.Qualifier + +@Retention(AnnotationRetention.BINARY) @Qualifier annotation class DefaultDispatcher + +@Retention(AnnotationRetention.BINARY) @Qualifier annotation class IoDispatcher + +@Retention(AnnotationRetention.BINARY) @Qualifier annotation class MainDispatcher + +@Retention(AnnotationRetention.BINARY) @Qualifier annotation class MainImmediateDispatcher diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt new file mode 100644 index 00000000000000..929306fbdc92f8 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt @@ -0,0 +1,31 @@ +package com.matter.virtual.device.app.core.common.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.appbar.AppBarLayout + +class DisableAppBarLayoutBehavior(context: Context, attributeSet: AttributeSet) : + AppBarLayout.Behavior(context, attributeSet) { + + override fun onStartNestedScroll( + parent: CoordinatorLayout, + child: AppBarLayout, + directTargetChild: View, + target: View, + nestedScrollAxes: Int, + type: Int + ): Boolean { + return false + } + + override fun onTouchEvent( + parent: CoordinatorLayout, + child: AppBarLayout, + ev: MotionEvent + ): Boolean { + return false + } +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/menu_item_bg.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/menu_item_bg.xml new file mode 100644 index 00000000000000..12bfa05d1664d4 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/menu_item_bg.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_device_unknown_24.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_device_unknown_24.xml new file mode 100644 index 00000000000000..22d47670e5fc8d --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_device_unknown_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_toggle_on_24.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_toggle_on_24.xml new file mode 100644 index 00000000000000..d42714cc7696e0 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/drawable/round_toggle_on_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/values-night/colors.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/values-night/colors.xml new file mode 100644 index 00000000000000..cbc187543ea0e6 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/values-night/colors.xml @@ -0,0 +1,5 @@ + + + #171717 + @android:color/white + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/values/colors.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/values/colors.xml new file mode 100644 index 00000000000000..14778835968022 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/values/colors.xml @@ -0,0 +1,12 @@ + + + @android:color/white + @android:color/white + #4ca7ed + @android:color/black + #f6f6f6 + @color/color_background_secondary + @color/textColor + #fcfcfc + @android:color/black + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml new file mode 100644 index 00000000000000..755c53609e9b3f --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml @@ -0,0 +1,25 @@ + + + 350dp + 25sp + 17sp + + 10dp + 48dp + 48dp + 7dp + 7dp + 13dp + 14dp + 24dp + 17sp + 16dp + 16dp + 16dp + + 11sp + 20sp + 15sp + + 50dp + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/values/strings.xml new file mode 100644 index 00000000000000..7afe5953bf2dfd --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + Matter OnOff Switch + Matter Device + icon + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/values/themes.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/values/themes.xml new file mode 100644 index 00000000000000..fcbe6bc78d57d4 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/values/themes.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/common/src/test/java/com/matter/virtual/device/app/core/common/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/core/common/src/test/java/com/matter/virtual/device/app/core/common/ExampleUnitTest.kt new file mode 100644 index 00000000000000..6df49ef5a27e1a --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/test/java/com/matter/virtual/device/app/core/common/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.common + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/core/data/.gitignore b/examples/virtual-device-app/android/App/core/data/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/core/data/build.gradle.kts b/examples/virtual-device-app/android/App/core/data/build.gradle.kts new file mode 100644 index 00000000000000..43027424737f65 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/build.gradle.kts @@ -0,0 +1,55 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("com.google.dagger.hilt.android") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.core.data" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation(project(":core:common")) + implementation(project(":core:matter")) + implementation(project(":core:model")) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/data/proguard-rules.pro b/examples/virtual-device-app/android/App/core/data/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/data/src/androidTest/java/com/matter/virtual/device/app/core/data/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/core/data/src/androidTest/java/com/matter/virtual/device/app/core/data/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..26be07910d95f1 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/androidTest/java/com/matter/virtual/device/app/core/data/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.core.data + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.core.data.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/data/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt new file mode 100644 index 00000000000000..c0352d531da3b5 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.data.di + +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.data.repository.MatterRepositoryImpl +import com.matter.virtual.device.app.core.data.repository.NetworkRepository +import com.matter.virtual.device.app.core.data.repository.NetworkRepositoryImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@InstallIn(SingletonComponent::class) +@Module +internal abstract class DataModule { + + @Binds abstract fun bindMatterRepository(repository: MatterRepositoryImpl): MatterRepository + + @Binds abstract fun bindNetworkRepository(repository: NetworkRepositoryImpl): NetworkRepository +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt new file mode 100644 index 00000000000000..7e436f8208276d --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt @@ -0,0 +1,9 @@ +package com.matter.virtual.device.app.core.data.repository + +import com.matter.virtual.device.app.core.model.Payload + +interface MatterRepository { + fun getQrcodeString(payload: Payload): String + + fun getManualPairingCodeString(payload: Payload): String +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt new file mode 100644 index 00000000000000..dc6d1cfd73174a --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt @@ -0,0 +1,17 @@ +package com.matter.virtual.device.app.core.data.repository + +import com.matter.virtual.device.app.core.matter.MatterApi +import com.matter.virtual.device.app.core.model.Payload +import javax.inject.Inject + +internal class MatterRepositoryImpl @Inject constructor(private val matterApi: MatterApi) : + MatterRepository { + + override fun getQrcodeString(payload: Payload): String { + return matterApi.getQrcodeString(payload) + } + + override fun getManualPairingCodeString(payload: Payload): String { + return matterApi.getManualPairingCodeString(payload) + } +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepository.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepository.kt new file mode 100644 index 00000000000000..4ff1cd8bf84a33 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepository.kt @@ -0,0 +1,5 @@ +package com.matter.virtual.device.app.core.data.repository + +interface NetworkRepository { + suspend fun getSSID(): String +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepositoryImpl.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepositoryImpl.kt new file mode 100644 index 00000000000000..20395ad2b7a637 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/NetworkRepositoryImpl.kt @@ -0,0 +1,34 @@ +package com.matter.virtual.device.app.core.data.repository + +import android.content.Context +import android.net.wifi.SupplicantState +import android.net.wifi.WifiManager +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import timber.log.Timber + +internal class NetworkRepositoryImpl +@Inject +constructor(@ApplicationContext private val context: Context) : NetworkRepository { + + override suspend fun getSSID(): String { + Timber.d("Hit") + return try { + val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager? + wifiManager?.let { + val wifiInfo = wifiManager.connectionInfo + var ssid = "" + if (wifiInfo.supplicantState == SupplicantState.COMPLETED) { + Timber.d("ssid:${wifiInfo.ssid}") + ssid = wifiInfo.ssid.replace("\"", "") + } + + ssid + } + ?: "Unknown" + } catch (e: Exception) { + Timber.e(e, "Exception") + "Unknown" + } + } +} diff --git a/examples/virtual-device-app/android/App/core/data/src/test/java/com/matter/virtual/device/app/core/data/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/core/data/src/test/java/com/matter/virtual/device/app/core/data/ExampleUnitTest.kt new file mode 100644 index 00000000000000..ec5dd8e3957aa3 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/test/java/com/matter/virtual/device/app/core/data/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.data + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/.gitignore b/examples/virtual-device-app/android/App/core/domain/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/core/domain/build.gradle.kts b/examples/virtual-device-app/android/App/core/domain/build.gradle.kts new file mode 100644 index 00000000000000..6cc2a239897333 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/build.gradle.kts @@ -0,0 +1,52 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "com.matter.virtual.device.app.core.domain" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation(project(":core:common")) + implementation(project(":core:data")) + implementation(project(":core:model")) + + implementation(Deps.Kotlin.coroutinesCore) + + implementation(Deps.inject) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/domain/proguard-rules.pro b/examples/virtual-device-app/android/App/core/domain/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/domain/src/androidTest/java/com/matter/virtual/device/app/core/domain/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/core/domain/src/androidTest/java/com/matter/virtual/device/app/core/domain/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..ee74e1189e90bd --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/androidTest/java/com/matter/virtual/device/app/core/domain/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.core.domain + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.core.domain.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/domain/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/CoroutineUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/CoroutineUseCase.kt new file mode 100644 index 00000000000000..548bff027c5fe7 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/CoroutineUseCase.kt @@ -0,0 +1,18 @@ +package com.matter.virtual.device.app.core.domain + +import com.matter.virtual.device.app.core.common.Result +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +abstract class CoroutineUseCase(private val coroutineDispatcher: CoroutineDispatcher) { + + suspend operator fun invoke(parameters: P): Result { + return try { + withContext(coroutineDispatcher) { execute(parameters).let { Result.Success(it) } } + } catch (e: Exception) { + Result.Error(e) + } + } + + @Throws(RuntimeException::class) protected abstract suspend fun execute(param: P): R +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/NonParamCoroutineUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/NonParamCoroutineUseCase.kt new file mode 100644 index 00000000000000..869b865b00a52d --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/NonParamCoroutineUseCase.kt @@ -0,0 +1,18 @@ +package com.matter.virtual.device.app.core.domain + +import com.matter.virtual.device.app.core.common.Result +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +abstract class NonParamCoroutineUseCase(private val coroutineDispatcher: CoroutineDispatcher) { + + suspend operator fun invoke(): Result { + return try { + withContext(coroutineDispatcher) { execute().let { Result.Success(it) } } + } catch (e: Exception) { + Result.Error(e) + } + } + + @Throws(RuntimeException::class) protected abstract suspend fun execute(): R +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetManualPairingCodeStringUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetManualPairingCodeStringUseCase.kt new file mode 100644 index 00000000000000..4c75c7532696d7 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetManualPairingCodeStringUseCase.kt @@ -0,0 +1,20 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import com.matter.virtual.device.app.core.model.Payload +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class GetManualPairingCodeStringUseCase +@Inject +constructor( + private val matterRepository: MatterRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: Payload): String { + return matterRepository.getManualPairingCodeString(param) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetQrCodeStringUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetQrCodeStringUseCase.kt new file mode 100644 index 00000000000000..0e8a5e7f5772ce --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/GetQrCodeStringUseCase.kt @@ -0,0 +1,20 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import com.matter.virtual.device.app.core.model.Payload +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class GetQrcodeStringUseCase +@Inject +constructor( + private val matterRepository: MatterRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: Payload): String { + return matterRepository.getQrcodeString(param) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/network/GetSSIDUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/network/GetSSIDUseCase.kt new file mode 100644 index 00000000000000..43dfdabacb1363 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/network/GetSSIDUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.network + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.NetworkRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class GetSSIDUseCase +@Inject +constructor( + private val networkRepository: NetworkRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): String { + return networkRepository.getSSID() + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/test/java/com/matter/virtual/device/app/core/domain/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/core/domain/src/test/java/com/matter/virtual/device/app/core/domain/ExampleUnitTest.kt new file mode 100644 index 00000000000000..97d7f5351868b1 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/test/java/com/matter/virtual/device/app/core/domain/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.domain + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/core/matter/.gitignore b/examples/virtual-device-app/android/App/core/matter/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/core/matter/build.gradle.kts b/examples/virtual-device-app/android/App/core/matter/build.gradle.kts new file mode 100644 index 00000000000000..9f94201ac02cf8 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/build.gradle.kts @@ -0,0 +1,60 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("com.google.dagger.hilt.android") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.core.matter" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + sourceSets { + getByName("main") { + jniLibs.setSrcDirs(listOf("../../app/libs/jniLibs")) + } + } +} + +dependencies { + implementation(fileTree(mapOf("dir" to "../../app/libs", "include" to listOf("*.jar")))) + + implementation(project(":core:common")) + implementation(project(":core:model")) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/matter/proguard-rules.pro b/examples/virtual-device-app/android/App/core/matter/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/matter/src/androidTest/java/com/matter/virtual/device/app/core/matter/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/core/matter/src/androidTest/java/com/matter/virtual/device/app/core/matter/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..1aa22f0498dde6 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/androidTest/java/com/matter/virtual/device/app/core/matter/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.core.matter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.core.matter.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApi.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApi.kt new file mode 100644 index 00000000000000..16974b4e307b49 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApi.kt @@ -0,0 +1,40 @@ +package com.matter.virtual.device.app.core.matter + +import chip.onboardingpayload.OnboardingPayloadException +import chip.onboardingpayload.OnboardingPayloadParser +import com.matter.virtual.device.app.core.matter.model.asSetupPayload +import com.matter.virtual.device.app.core.model.Payload +import javax.inject.Inject +import javax.inject.Singleton +import timber.log.Timber + +@Singleton +class MatterApi @Inject constructor() { + + fun getQrcodeString(payload: Payload): String { + val onboardingPayloadParser = OnboardingPayloadParser() + var qrcode = "" + try { + qrcode = onboardingPayloadParser.getQrCodeFromPayload(payload.asSetupPayload()) + } catch (e: OnboardingPayloadException) { + e.printStackTrace() + } + + Timber.d("qrcode:$qrcode") + return qrcode + } + + fun getManualPairingCodeString(payload: Payload): String { + val onboardingPayloadParser = OnboardingPayloadParser() + var manualPairingCode = "" + try { + manualPairingCode = + onboardingPayloadParser.getManualPairingCodeFromPayload(payload.asSetupPayload()) + } catch (e: OnboardingPayloadException) { + e.printStackTrace() + } + + Timber.d("manualPairingCode:$manualPairingCode") + return manualPairingCode + } +} diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/model/Payload.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/model/Payload.kt new file mode 100644 index 00000000000000..076fd5c7e86815 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/model/Payload.kt @@ -0,0 +1,33 @@ +package com.matter.virtual.device.app.core.matter.model + +import chip.onboardingpayload.DiscoveryCapability +import chip.onboardingpayload.OnboardingPayload +import com.matter.virtual.device.app.core.common.MatterConstants +import com.matter.virtual.device.app.core.model.OnboardingType +import com.matter.virtual.device.app.core.model.Payload +import timber.log.Timber + +fun Payload.asSetupPayload(): OnboardingPayload { + val discoveryCapabilities = HashSet() + when (this.onboardingType) { + OnboardingType.WIFI -> discoveryCapabilities.add(DiscoveryCapability.ON_NETWORK) + OnboardingType.BLE -> discoveryCapabilities.add(DiscoveryCapability.BLE) + OnboardingType.WIFI_BLE -> { + discoveryCapabilities.add(DiscoveryCapability.ON_NETWORK) + discoveryCapabilities.add(DiscoveryCapability.BLE) + } + else -> { + Timber.e("Unknown Type") + } + } + + return OnboardingPayload( + MatterConstants.DEFAULT_VERSION, + MatterConstants.DEFAULT_VENDOR_ID, + MatterConstants.DEFAULT_PRODUCT_ID, + MatterConstants.DEFAULT_COMMISSIONING_FLOW, + discoveryCapabilities, + discriminator, + MatterConstants.DEFAULT_SETUP_PINCODE + ) +} diff --git a/examples/virtual-device-app/android/App/core/matter/src/test/java/com/matter/virtual/device/app/core/matter/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/core/matter/src/test/java/com/matter/virtual/device/app/core/matter/ExampleUnitTest.kt new file mode 100644 index 00000000000000..c355211d3b59db --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/test/java/com/matter/virtual/device/app/core/matter/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.matter + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/core/model/.gitignore b/examples/virtual-device-app/android/App/core/model/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/core/model/build.gradle.kts b/examples/virtual-device-app/android/App/core/model/build.gradle.kts new file mode 100644 index 00000000000000..d51ec3d4154ea2 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/build.gradle.kts @@ -0,0 +1,44 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "com.matter.virtual.device.app.core.model" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/model/proguard-rules.pro b/examples/virtual-device-app/android/App/core/model/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/model/src/androidTest/java/com/matter/virtual/device/app/core/model/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/core/model/src/androidTest/java/com/matter/virtual/device/app/core/model/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..ce8f30dded727c --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/src/androidTest/java/com/matter/virtual/device/app/core/model/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.core.model + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.core.model.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/core/model/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/model/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/OnobardingType.kt b/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/OnobardingType.kt new file mode 100644 index 00000000000000..46ce38113a5b5b --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/OnobardingType.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.model + +enum class OnboardingType { + WIFI, + BLE, + WIFI_BLE, + UNKNOWN +} + +fun Int.asOnboardingType() = + when (this) { + 0 -> OnboardingType.WIFI + 1 -> OnboardingType.BLE + 2 -> OnboardingType.WIFI_BLE + else -> OnboardingType.UNKNOWN + } diff --git a/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/Payload.kt b/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/Payload.kt new file mode 100644 index 00000000000000..4ffc70768e31d1 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/Payload.kt @@ -0,0 +1,3 @@ +package com.matter.virtual.device.app.core.model + +data class Payload(val onboardingType: OnboardingType, val discriminator: Int) diff --git a/examples/virtual-device-app/android/App/core/model/src/test/java/com/matter/virtual/device/app/core/model/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/core/model/src/test/java/com/matter/virtual/device/app/core/model/ExampleUnitTest.kt new file mode 100644 index 00000000000000..59f3546d111ca4 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/src/test/java/com/matter/virtual/device/app/core/model/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.model + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/feature/main/.gitignore b/examples/virtual-device-app/android/App/feature/main/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/feature/main/build.gradle.kts b/examples/virtual-device-app/android/App/feature/main/build.gradle.kts new file mode 100644 index 00000000000000..c9931cf58938e4 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/build.gradle.kts @@ -0,0 +1,69 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("com.google.dagger.hilt.android") + id("androidx.navigation.safeargs.kotlin") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.feature.main" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + dataBinding = true + } +} + +dependencies { + + implementation(project(":core:common")) + implementation(project(":core:domain")) + implementation(project(":core:model")) + + implementation(Deps.AndroidX.core) + implementation(Deps.AndroidX.appcompat) + implementation(Deps.AndroidX.fragment) + + implementation(Deps.Kotlin.serialization) + + implementation(Deps.Navigation.fragment) + implementation(Deps.Navigation.ui) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/main/proguard-rules.pro b/examples/virtual-device-app/android/App/feature/main/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/main/src/androidTest/java/com/matter/virtual/device/app/feature/main/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/feature/main/src/androidTest/java/com/matter/virtual/device/app/feature/main/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..b1b135167ba95d --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/androidTest/java/com/matter/virtual/device/app/feature/main/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.feature.main + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.feature.main.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/feature/main/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/BindingAdapter.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/BindingAdapter.kt new file mode 100644 index 00000000000000..771aa2ad937ad9 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/BindingAdapter.kt @@ -0,0 +1,13 @@ +package com.matter.virtual.device.app.feature.main + +import androidx.annotation.DrawableRes +import androidx.appcompat.widget.AppCompatImageView +import androidx.databinding.BindingAdapter + +object BindingAdapter { + @BindingAdapter("imageSrc") + @JvmStatic + fun AppCompatImageView.bindImageSrc(@DrawableRes imgResId: Int) { + this.setImageResource(imgResId) + } +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt new file mode 100644 index 00000000000000..55ebdace76a00e --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt @@ -0,0 +1,122 @@ +package com.matter.virtual.device.app.feature.main + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.OnBackPressedCallback +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.matter.virtual.device.app.core.common.DeepLink +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.feature.main.databinding.FragmentMainBinding +import com.matter.virtual.device.app.feature.main.model.Menu +import dagger.hilt.android.AndroidEntryPoint +import kotlin.math.abs +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import timber.log.Timber + +@AndroidEntryPoint +class MainFragment : Fragment() { + + private lateinit var binding: FragmentMainBinding + private lateinit var onBackPressedCallback: OnBackPressedCallback + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Timber.d("Hit") + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false) + binding.lifecycleOwner = viewLifecycleOwner + + return binding.root + } + + @OptIn(ExperimentalSerializationApi::class) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Timber.d("Hit") + super.onViewCreated(view, savedInstanceState) + + (activity as AppCompatActivity).setSupportActionBar(binding.toolbar) + (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) + + binding.appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> + var ratio = 0F + if (abs(verticalOffset) != 0) { + ratio = abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange.toFloat() + } + + binding.collapseTitle.alpha = 1f - ratio * 2f + 0.1f + binding.toolbarTitle.alpha = (ratio - 0.5f) * 2f + 0.1f + } + + val itemList = arrayListOf(Menu.ON_OFF_SWITCH) + + val menuAdapter = + MenuAdapter( + object : MenuAdapter.ItemHandler { + override fun onClick(item: Menu) { + val matterSettings = MatterSettings(device = item.device) + val jsonSettings = Json.encodeToString(matterSettings) + try { + findNavController() + .navigate(DeepLink.getDeepLinkRequestForSetupFragment(jsonSettings)) + } catch (e: Exception) { + Timber.e(e, "navigate failure") + } + } + } + ) + .apply { submitList(itemList) } + + val sideSpace = resources.getDimension(R.dimen.menu_item_side_space).toInt() + val bottomSpace = resources.getDimension(R.dimen.menu_item_bottom_space).toInt() + + binding.recyclerView.apply { + layoutManager = LinearLayoutManager(requireContext()) + if (itemDecorationCount == 0) { + addItemDecoration(VerticalSpaceItemDecoration(sideSpace, bottomSpace)) + } + adapter = menuAdapter + } + } + + override fun onResume() { + super.onResume() + Timber.d("onResume()") + } + + override fun onAttach(context: Context) { + Timber.d("Hit") + super.onAttach(context) + + onBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + Timber.d("handleOnBackPressed()") + requireActivity().finishAffinity() + } + } + + requireActivity().onBackPressedDispatcher.addCallback(this, onBackPressedCallback) + } + + override fun onDetach() { + super.onDetach() + Timber.d("onDetach()") + onBackPressedCallback.remove() + } + + override fun onDestroy() { + super.onDestroy() + Timber.d("onDestroy()") + } +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MenuAdapter.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MenuAdapter.kt new file mode 100644 index 00000000000000..c3212333d7ec13 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MenuAdapter.kt @@ -0,0 +1,46 @@ +package com.matter.virtual.device.app.feature.main + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.matter.virtual.device.app.feature.main.databinding.ItemMenuBinding +import com.matter.virtual.device.app.feature.main.model.Menu + +internal class MenuAdapter(private val itemHandler: ItemHandler) : + ListAdapter( + object : DiffUtil.ItemCallback

() { + override fun areItemsTheSame(oldItem: Menu, newItem: Menu): Boolean { + return oldItem.titleResId == newItem.titleResId + } + + override fun areContentsTheSame(oldItem: Menu, newItem: Menu): Boolean { + return oldItem == newItem + } + } + ) { + + inner class MenuViewHolder(private val binding: ItemMenuBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bind(item: Menu) { + binding.item = item + binding.itemHandler = itemHandler + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuViewHolder { + val layoutInflater = LayoutInflater.from(parent.context) + val binding = ItemMenuBinding.inflate(layoutInflater, parent, false) + return MenuViewHolder(binding) + } + + override fun onBindViewHolder(holder: MenuViewHolder, position: Int) { + val item = getItem(position) + holder.bind(item) + } + + interface ItemHandler { + fun onClick(item: Menu) + } +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/VerticalSpaceItemDecoration.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/VerticalSpaceItemDecoration.kt new file mode 100644 index 00000000000000..fce2d70bd1dc38 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/VerticalSpaceItemDecoration.kt @@ -0,0 +1,25 @@ +package com.matter.virtual.device.app.feature.main + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class VerticalSpaceItemDecoration(private val sideSpace: Int, private val bottomSpace: Int) : + RecyclerView.ItemDecoration() { + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + parent.adapter?.let { adapter -> + if (parent.getChildAdapterPosition(view) != adapter.itemCount - 1) { + outRect.bottom = bottomSpace + } + + outRect.left = sideSpace + outRect.right = sideSpace + } + } +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/model/Menu.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/model/Menu.kt new file mode 100644 index 00000000000000..67e2658c5bed44 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/model/Menu.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.feature.main.model + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import com.matter.virtual.device.app.core.common.Device +import com.matter.virtual.device.app.feature.main.R + +enum class Menu( + @DrawableRes val iconResId: Int, + @StringRes val titleResId: Int, + val isDim: Boolean = false, + val device: Device = Device.Unknown +) { + ON_OFF_SWITCH( + R.drawable.round_toggle_on_24, + R.string.matter_on_off_switch, + device = Device.OnOffSwitch + ) +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_main.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_main.xml new file mode 100644 index 00000000000000..724e9f21634261 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_main.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/item_menu.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/item_menu.xml new file mode 100644 index 00000000000000..b9b12400969d84 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/item_menu.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/navigation/main_nav_graph.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/navigation/main_nav_graph.xml new file mode 100644 index 00000000000000..c3f66c3f7c5bbe --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/navigation/main_nav_graph.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml new file mode 100644 index 00000000000000..22caae70477e41 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Matter Virtual Device + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/main/src/test/java/com/matter/virtual/device/app/feature/main/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/feature/main/src/test/java/com/matter/virtual/device/app/feature/main/ExampleUnitTest.kt new file mode 100644 index 00000000000000..43846a9c66d208 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/test/java/com/matter/virtual/device/app/feature/main/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.feature.main + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/feature/qrcode/.gitignore b/examples/virtual-device-app/android/App/feature/qrcode/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/feature/qrcode/build.gradle.kts b/examples/virtual-device-app/android/App/feature/qrcode/build.gradle.kts new file mode 100644 index 00000000000000..f93270453f1efe --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/build.gradle.kts @@ -0,0 +1,69 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("com.google.dagger.hilt.android") + id("androidx.navigation.safeargs.kotlin") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.feature.qrcode" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + dataBinding = true + } +} + +dependencies { + + implementation(project(":core:common")) + implementation(project(":core:domain")) + implementation(project(":core:model")) + + implementation(Deps.AndroidX.core) + implementation(Deps.AndroidX.appcompat) + implementation(Deps.AndroidX.fragment) + + implementation(Deps.Kotlin.serialization) + + implementation(Deps.Navigation.fragment) + implementation(Deps.Navigation.ui) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/qrcode/proguard-rules.pro b/examples/virtual-device-app/android/App/feature/qrcode/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/androidTest/java/com/matter/virtual/device/app/feature/qrcode/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/feature/qrcode/src/androidTest/java/com/matter/virtual/device/app/feature/qrcode/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..46eefbbf255810 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/androidTest/java/com/matter/virtual/device/app/feature/qrcode/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.feature.qrcode + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.feature.qrcode.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/feature/qrcode/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeFragment.kt b/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeFragment.kt new file mode 100644 index 00000000000000..e8622ff6f71f45 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeFragment.kt @@ -0,0 +1,159 @@ +package com.matter.virtual.device.app.feature.qrcode + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.OnBackPressedCallback +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import com.matter.virtual.device.app.core.common.MatterConstants +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.common.QrcodeUtil +import com.matter.virtual.device.app.feature.qrcode.databinding.FragmentQrcodeBinding +import dagger.hilt.android.AndroidEntryPoint +import kotlin.math.abs +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import timber.log.Timber + +@AndroidEntryPoint +class QrcodeFragment : Fragment() { + + private lateinit var binding: FragmentQrcodeBinding + private val viewModel by viewModels() + + private lateinit var onBackPressedCallback: OnBackPressedCallback + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Timber.d("Hit") + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_qrcode, container, false) + binding.lifecycleOwner = viewLifecycleOwner + binding.viewModel = viewModel + + return binding.root + } + + @OptIn(ExperimentalSerializationApi::class) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Timber.d("Hit") + super.onViewCreated(view, savedInstanceState) + + (activity as AppCompatActivity).setSupportActionBar(binding.toolbar) + (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) + + binding.appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> + var ratio = 0F + if (abs(verticalOffset) != 0) { + ratio = abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange.toFloat() + } + + binding.collapseTitle.alpha = 1f - ratio * 2f + 0.1f + binding.toolbarTitle.alpha = (ratio - 0.5f) * 2f + 0.1f + } + + val args: QrcodeFragmentArgs by navArgs() + val matterSettings = Json.decodeFromString(args.setting) + + viewModel.uiState.observe(viewLifecycleOwner) { + when (it) { + QrcodeUiState.Loading -> { + binding.progressBar.visibility = View.VISIBLE + } + is QrcodeUiState.Qrcode -> { + binding.progressBar.visibility = View.GONE + + binding.qrTypeImage.setImageResource(matterSettings.device.deviceIconResId) + binding.qrTypeTitle.text = getString(matterSettings.device.deviceNameResId) + + val qrCodeBitmap: Bitmap? = QrcodeUtil.createQrCodeBitmap(it.qrCode, QR_WIDTH, QR_HEIGHT) + binding.qrImage.setImageBitmap(qrCodeBitmap) + + binding.qrText.text = getString(R.string.qrcode_qr_text, it.qrCode) + binding.manualCodeText.text = + getString(R.string.qrcode_manual_code_text, it.manualPairingCode) + binding.versionText.text = + getString(R.string.qrcode_version_text, MatterConstants.DEFAULT_VERSION.toString()) + binding.vendorIdText.text = + getString( + R.string.qrcode_vendor_id_text, + MatterConstants.DEFAULT_VENDOR_ID.toString(), + MatterConstants.DEFAULT_VENDOR_ID + ) + binding.productIdText.text = + getString( + R.string.qrcode_product_id_text, + MatterConstants.DEFAULT_PRODUCT_ID.toString(), + MatterConstants.DEFAULT_PRODUCT_ID + ) + binding.commissioningFlowText.text = + getString( + R.string.qrcode_commissioning_flow_text, + MatterConstants.DEFAULT_COMMISSIONING_FLOW.toString() + ) + binding.onboardingTypeText.text = + getString(R.string.qrcode_onboarding_type_text, matterSettings.onboardingType) + binding.setupPinCodeText.text = + getString( + R.string.qrcode_setup_pin_code_text, + MatterConstants.DEFAULT_SETUP_PINCODE.toString() + ) + binding.discriminatorText.text = + getString( + R.string.qrcode_discriminator_text, + matterSettings.discriminator.toString(), + matterSettings.discriminator + ) + } + else -> {} + } + } + } + + override fun onResume() { + Timber.d("Hit") + super.onResume() + } + + override fun onAttach(context: Context) { + Timber.d("Hit") + super.onAttach(context) + + onBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + Timber.d("handleOnBackPressed()") + findNavController().popBackStack() + } + } + + requireActivity().onBackPressedDispatcher.addCallback(this, onBackPressedCallback) + } + + override fun onDetach() { + Timber.d("Hit") + super.onDetach() + onBackPressedCallback.remove() + } + + override fun onDestroy() { + Timber.d("Hit") + super.onDestroy() + } + + companion object { + private const val QR_WIDTH = 450 + private const val QR_HEIGHT = 450 + } +} diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt b/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt new file mode 100644 index 00000000000000..3505f33eef6e78 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt @@ -0,0 +1,65 @@ +package com.matter.virtual.device.app.feature.qrcode + +import androidx.lifecycle.* +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.common.successOr +import com.matter.virtual.device.app.core.domain.usecase.matter.GetManualPairingCodeStringUseCase +import com.matter.virtual.device.app.core.domain.usecase.matter.GetQrcodeStringUseCase +import com.matter.virtual.device.app.core.model.Payload +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import timber.log.Timber + +@OptIn(ExperimentalSerializationApi::class) +@HiltViewModel +class QrcodeViewModel +@Inject +constructor( + private val getQrcodeStringUseCase: GetQrcodeStringUseCase, + private val getManualPairingCodeStringUseCase: GetManualPairingCodeStringUseCase, + savedStateHandle: SavedStateHandle +) : ViewModel() { + + private val _uiState = MutableLiveData(QrcodeUiState.Loading) + val uiState: LiveData + get() = _uiState + + init { + viewModelScope.launch { + val jsonSettings = savedStateHandle.get("setting") + jsonSettings?.let { + val matterSettings = Json.decodeFromString(it) + + // TODO : start service + delay(500) + + val payload = + Payload( + onboardingType = matterSettings.onboardingType, + discriminator = matterSettings.discriminator + ) + + val qrCode = getQrcodeStringUseCase(payload).successOr("") + val manualPairingCode = getManualPairingCodeStringUseCase(payload).successOr("") + + _uiState.value = QrcodeUiState.Qrcode(qrCode, manualPairingCode) + } + } + } + + override fun onCleared() { + super.onCleared() + Timber.d("onCleared()") + } +} + +sealed interface QrcodeUiState { + object Loading : QrcodeUiState + + data class Qrcode(val qrCode: String, val manualPairingCode: String) : QrcodeUiState +} diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml new file mode 100644 index 00000000000000..997f74826654a0 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/navigation/qrcode_nav_graph.xml b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/navigation/qrcode_nav_graph.xml new file mode 100644 index 00000000000000..1323bd261feb3c --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/navigation/qrcode_nav_graph.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/values/strings.xml new file mode 100644 index 00000000000000..0237e8b5ab38f9 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/values/strings.xml @@ -0,0 +1,13 @@ + + + QR Code + QR Code : %1$s + Manual Pairing Code : %1$s + Version : %1$s + Vendor ID : %1$s (%2$#x) + Product ID : %1$s (%2$#x) + Commissioning Flow : %1$s + Onboarding Type : %1$s + Setup PinCode : %1$s\ + Discriminator : %1$s (%2$#x) + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/test/java/com/matter/virtual/device/app/feature/qrcode/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/feature/qrcode/src/test/java/com/matter/virtual/device/app/feature/qrcode/ExampleUnitTest.kt new file mode 100644 index 00000000000000..f4c25e37cccba7 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/test/java/com/matter/virtual/device/app/feature/qrcode/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.feature.qrcode + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/feature/setup/.gitignore b/examples/virtual-device-app/android/App/feature/setup/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/feature/setup/build.gradle.kts b/examples/virtual-device-app/android/App/feature/setup/build.gradle.kts new file mode 100644 index 00000000000000..be40d48f8d5c23 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/build.gradle.kts @@ -0,0 +1,69 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("com.google.dagger.hilt.android") + id("androidx.navigation.safeargs.kotlin") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.feature.setup" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + dataBinding = true + } +} + +dependencies { + + implementation(project(":core:common")) + implementation(project(":core:domain")) + implementation(project(":core:model")) + + implementation(Deps.AndroidX.core) + implementation(Deps.AndroidX.appcompat) + implementation(Deps.AndroidX.fragment) + + implementation(Deps.Kotlin.serialization) + + implementation(Deps.Navigation.fragment) + implementation(Deps.Navigation.ui) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/proguard-rules.pro b/examples/virtual-device-app/android/App/feature/setup/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/androidTest/java/com/matter/virtual/device/app/feature/setup/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/feature/setup/src/androidTest/java/com/matter/virtual/device/app/feature/setup/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..72a2f97b5ab40c --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/androidTest/java/com/matter/virtual/device/app/feature/setup/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.feature.setup + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.matter.virtual.device.app.feature.setup.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupFragment.kt b/examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupFragment.kt new file mode 100644 index 00000000000000..79ede035a2f506 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupFragment.kt @@ -0,0 +1,172 @@ +package com.matter.virtual.device.app.feature.setup + +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import com.matter.virtual.device.app.core.common.DeepLink +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.model.OnboardingType +import com.matter.virtual.device.app.feature.setup.databinding.DialogSetupContinueBinding +import com.matter.virtual.device.app.feature.setup.databinding.FragmentSetupBinding +import dagger.hilt.android.AndroidEntryPoint +import kotlin.math.abs +import kotlinx.coroutines.launch +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import timber.log.Timber + +@AndroidEntryPoint +class SetupFragment : Fragment() { + + private lateinit var binding: FragmentSetupBinding + private val viewModel by viewModels() + + private lateinit var matterSettings: MatterSettings + private var ssid: String = "Unknown" + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Timber.d("Hit") + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_setup, container, false) + binding.lifecycleOwner = viewLifecycleOwner + + return binding.root + } + + @OptIn(ExperimentalSerializationApi::class) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Timber.d("Hit") + super.onViewCreated(view, savedInstanceState) + + (activity as AppCompatActivity).setSupportActionBar(binding.toolbar) + (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) + + binding.appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> + var ratio = 0F + if (abs(verticalOffset) != 0) { + ratio = abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange.toFloat() + } + + binding.collapseTitle.alpha = 1f - ratio * 2f + 0.1f + binding.toolbarTitle.alpha = (ratio - 0.5f) * 2f + 0.1f + } + + val args: SetupFragmentArgs by navArgs() + this.matterSettings = Json.decodeFromString(args.setting) + + binding.setupDeviceNameValueText.text = getString(matterSettings.device.deviceNameResId) + binding.setupDiscriminatorEditText.setText(matterSettings.device.discriminator.toString()) + + binding.setupSaveButton.setOnClickListener { + val discriminatorText = binding.setupDiscriminatorEditText.text.toString() + if (discriminatorText.isEmpty()) { + Toast.makeText( + requireActivity(), + getString(R.string.toast_discriminator), + Toast.LENGTH_LONG + ) + .show() + } else { + val discriminator = discriminatorText.toInt() + if (discriminator > DISCRIMINATOR_LIMIT) { + Toast.makeText( + requireActivity(), + getString(R.string.toast_discriminator), + Toast.LENGTH_LONG + ) + .show() + } else { + lifecycleScope.launch { + this@SetupFragment.ssid = viewModel.getSSID() + showConfirmDialog() + } + } + } + } + } + + @OptIn(ExperimentalSerializationApi::class) + private fun showConfirmDialog() { + Timber.d("Hit") + + val dialogBinding: DialogSetupContinueBinding = + DataBindingUtil.inflate( + LayoutInflater.from(requireContext()), + R.layout.dialog_setup_continue, + null, + false + ) + + val confirmDialog = + AlertDialog.Builder(requireContext(), R.style.Theme_AppCompat_DayNight_Dialog_Alert) + .setView(dialogBinding.root) + .setCancelable(false) + .create() + + confirmDialog.window?.let { + it.setGravity(Gravity.BOTTOM) + it.setBackgroundDrawableResource(R.drawable.dialog_bg) + } + + dialogBinding.dialogSetupContinueTypeImage.setImageResource( + this.matterSettings.device.deviceIconResId + ) + dialogBinding.dialogSetupContinueSsidText.text = getString(R.string.setup_ssid_text, this.ssid) + dialogBinding.dialogSetupContinueDeviceNameText.text = + getString(this.matterSettings.device.deviceNameResId) + + val discriminator = binding.setupDiscriminatorEditText.text.toString() + dialogBinding.dialogSetupContinueDiscriminatorText.text = + getString( + R.string.setup_discriminator_text, + getString(R.string.hint_discriminator), + discriminator + ) + + dialogBinding.dialogSetupCancelButton.setOnClickListener { confirmDialog.dismiss() } + + dialogBinding.dialogSetupStartButton.setOnClickListener { + confirmDialog.dismiss() + + val onboardingType = + when (binding.setupOnboardingRadioGroup.checkedRadioButtonId) { + R.id.setup_onboarding_wifi_only -> OnboardingType.WIFI + R.id.setup_onboarding_ble_only -> OnboardingType.BLE + R.id.setup_onboarding_wifi_ble -> OnboardingType.WIFI_BLE + else -> OnboardingType.WIFI + } + Timber.d("MatterOnboardingType:$onboardingType") + this.matterSettings.onboardingType = onboardingType + this.matterSettings.discriminator = discriminator.toInt() + + val jsonSettings = Json.encodeToString(this.matterSettings) + try { + findNavController().navigate(DeepLink.getDeepLinkRequestForQrcodeFragment(jsonSettings)) + } catch (e: Exception) { + Timber.e(e, "navigate failure") + } + } + + confirmDialog.show() + } + + companion object { + private const val DISCRIMINATOR_LIMIT = 4095 + } +} diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupViewModel.kt b/examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupViewModel.kt new file mode 100644 index 00000000000000..739af1eb753825 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/java/com/matter/virtual/device/app/feature/setup/SetupViewModel.kt @@ -0,0 +1,27 @@ +package com.matter.virtual.device.app.feature.setup + +import androidx.lifecycle.* +import com.matter.virtual.device.app.core.common.successOr +import com.matter.virtual.device.app.core.domain.usecase.network.GetSSIDUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.async +import timber.log.Timber + +@HiltViewModel +class SetupViewModel @Inject constructor(private val getSSIDUseCase: GetSSIDUseCase) : ViewModel() { + + override fun onCleared() { + Timber.d("Hit") + super.onCleared() + } + + suspend fun getSSID(): String { + Timber.d("Hit") + val deferred = viewModelScope.async { getSSIDUseCase().successOr("Unknown") } + + val ssid = deferred.await() + Timber.d("ssid:${ssid}") + return ssid + } +} diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/dialog_bg.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/dialog_bg.xml new file mode 100644 index 00000000000000..9df10627208772 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/dialog_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/round_notification_important_24.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/round_notification_important_24.xml new file mode 100644 index 00000000000000..865cd172ba3a7c --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/drawable/round_notification_important_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/dialog_setup_continue.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/dialog_setup_continue.xml new file mode 100644 index 00000000000000..0fc3db9ec27617 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/dialog_setup_continue.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/fragment_setup.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/fragment_setup.xml new file mode 100644 index 00000000000000..7bf2118df30ac5 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/layout/fragment_setup.xml @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/navigation/setup_nav_graph.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/navigation/setup_nav_graph.xml new file mode 100644 index 00000000000000..cf9536bfe80ac8 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/navigation/setup_nav_graph.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/values-ko/strings.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values-ko/strings.xml new file mode 100644 index 00000000000000..b51e7732e3f87c --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values-ko/strings.xml @@ -0,0 +1,8 @@ + + + 동일한 Wi-Fi에 연결하세요 + 휴대폰/허브/디바이스 앱이 동일한 Wi-Fi 네크워크에 연결되어 있는지 확인해 주세요. + 저장 + 취소 + 시작 + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/values-night/colors.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values-night/colors.xml new file mode 100644 index 00000000000000..1a92e47e988de8 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values-night/colors.xml @@ -0,0 +1,5 @@ + + + #6E6E6E + #78C3FF + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/values/colors.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values/colors.xml new file mode 100644 index 00000000000000..d5b5d944f178d0 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + @color/textColor + #D5E3FF + #0C548D + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values/strings.xml new file mode 100644 index 00000000000000..e8ae1eb4677b47 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/main/res/values/strings.xml @@ -0,0 +1,18 @@ + + + Setup + Device Name + Discriminator (Max:4095) + Discriminator + Wi-Fi + BLE + Wi-Fi/BLE + Connect to the same Wi-Fi network + Make sure your Mobile/Hub/Device App are connected to the same Wi-Fi network. + Save + Invalid input value + Cancel + Start + Wi-Fi : %1$s + %1$s : %2$s + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/setup/src/test/java/com/matter/virtual/device/app/feature/setup/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/feature/setup/src/test/java/com/matter/virtual/device/app/feature/setup/ExampleUnitTest.kt new file mode 100644 index 00000000000000..79e148b3080371 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/setup/src/test/java/com/matter/virtual/device/app/feature/setup/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.feature.setup + +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/virtual-device-app/android/App/gradle.properties b/examples/virtual-device-app/android/App/gradle.properties new file mode 100644 index 00000000000000..f764d9116e4320 --- /dev/null +++ b/examples/virtual-device-app/android/App/gradle.properties @@ -0,0 +1,28 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official + +# Build SDK from source code and debug in Android Stduio. Must also set matterBuildSrcDir. +matterSdkSourceBuild=false +# Point to the SDK build dir without quotes (out/android-arm64-chip-test for +# example) to build SDK from source code and debug in Android Studio. +# Set to blank to use the SDK prebuilt by scripts/build/build_examples.py. +matterBuildSrcDir=out/android-arm64-virtual-device-app diff --git a/examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.jar b/examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.properties b/examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000000..aed27c26b978a7 --- /dev/null +++ b/examples/virtual-device-app/android/App/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Fri Apr 08 15:38:34 KST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +android.injected.testOnly=false diff --git a/examples/virtual-device-app/android/App/gradlew b/examples/virtual-device-app/android/App/gradlew new file mode 100755 index 00000000000000..180cdce0308183 --- /dev/null +++ b/examples/virtual-device-app/android/App/gradlew @@ -0,0 +1,184 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ]; do + ls=$(ls -ld "$PRG") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' >/dev/null; then + PRG="$link" + else + PRG=$(dirname "$PRG")"/$link" + fi +done +SAVED="$PWD" +cd "$(dirname "$PRG")" >/dev/null +APP_HOME="$(pwd -P)" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=$(basename "$0") + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn() { + echo "$*" +} + +die() { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$(uname)" in + CYGWIN*) + cygwin=true + ;; + Darwin*) + darwin=true + ;; + MINGW*) + msys=true + ;; + NONSTOP*) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ]; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then + MAX_FD_LIMIT=$(ulimit -H -n) + if [ $? -eq 0 ]; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n "$MAX_FD" + if [ $? -ne 0 ]; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if "$darwin"; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ]; then + APP_HOME=$(cygpath --path --mixed "$APP_HOME") + CLASSPATH=$(cygpath --path --mixed "$CLASSPATH") + + JAVACMD=$(cygpath --unix "$JAVACMD") + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null) + SEP="" + for dir in "$ROOTDIRSRAW"; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ]; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@"; do + CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -) + CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option + + if [ "$CHECK" -ne 0 ] && [ "$CHECK2" -eq 0 ]; then ### Added a condition + eval "$(echo args"$i")=$(cygpath --path --ignore --mixed "$arg")" + else + eval "$(echo args"$i")=\"$arg\"" + fi + i=$(expr "$i" + 1) + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save() { + for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- "$DEFAULT_JVM_OPTS" "$JAVA_OPTS" "$GRADLE_OPTS" "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/examples/virtual-device-app/android/App/gradlew.bat b/examples/virtual-device-app/android/App/gradlew.bat new file mode 100644 index 00000000000000..107acd32c4e687 --- /dev/null +++ b/examples/virtual-device-app/android/App/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/virtual-device-app/android/App/settings.gradle.kts b/examples/virtual-device-app/android/App/settings.gradle.kts new file mode 100644 index 00000000000000..0ae5b79223eba3 --- /dev/null +++ b/examples/virtual-device-app/android/App/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "VirtualDeviceApp" +include(":app") +include(":core:common") +include(":core:data") +include(":core:domain") +include(":core:matter") +include(":core:model") +include(":feature:main") +include(":feature:qrcode") +include(":feature:setup") diff --git a/examples/virtual-device-app/android/BUILD.gn b/examples/virtual-device-app/android/BUILD.gn new file mode 100644 index 00000000000000..9926574fcbf792 --- /dev/null +++ b/examples/virtual-device-app/android/BUILD.gn @@ -0,0 +1,92 @@ +# 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. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +import("${build_root}/config/android_abi.gni") +import("${chip_root}/build/chip/java/rules.gni") +import("${chip_root}/build/chip/tools.gni") + +shared_library("jni") { + output_name = "libDeviceApp" + + sources = [ + "${chip_root}/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h", + "java/AppImpl.cpp", + "java/AppImpl.h", + "java/ClusterChangeAttribute.cpp", + "java/DeviceApp-JNI.cpp", + "java/JNIDACProvider.cpp", + "java/JNIDACProvider.h", + "java/OnOffManager.cpp", + "java/OnOffManager.h", + ] + + deps = [ + "${chip_root}/examples/platform/linux:commissioner-main", + "${chip_root}/examples/virtual-device-app/virtual-device-common", + "${chip_root}/src/app/server/java:jni", + "${chip_root}/src/lib", + "${chip_root}/src/lib/support/jsontlv", + "${chip_root}/third_party/inipp", + ] + + cflags = [ "-Wconversion" ] + + output_dir = "${root_out_dir}/lib/jni/${android_abi}" + + ldflags = [ "-Wl,--gc-sections" ] +} + +android_library("java") { + output_name = "DeviceApp.jar" + + deps = [ + ":android", + "${chip_root}/third_party/android_deps:annotation", + ] + + data_deps = [ + ":jni", + "${chip_root}/build/chip/java:shared_cpplib", + ] + + sources = [ + "java/src/com/matter/virtual/device/app/DACProvider.java", + "java/src/com/matter/virtual/device/app/DeviceApp.java", + "java/src/com/matter/virtual/device/app/DeviceAppCallback.java", + "java/src/com/matter/virtual/device/app/OnOffManager.java", + ] + + javac_flags = [ "-Xlint:deprecation" ] + + # TODO: add classpath support (we likely need to add something like + # ..../platforms/android-26/android.jar to access BLE items) +} + +java_prebuilt("android") { + jar_path = "${android_sdk_root}/platforms/android-26/android.jar" +} + +group("default") { + deps = [ + ":android", + ":java", + ":jni", + "${chip_root}/src/app/server/java", + "${chip_root}/src/controller/java:onboarding_payload", + "${chip_root}/src/platform/android:java", + ] +} diff --git a/examples/virtual-device-app/android/README.md b/examples/virtual-device-app/android/README.md new file mode 100644 index 00000000000000..a5a1ce3a659008 --- /dev/null +++ b/examples/virtual-device-app/android/README.md @@ -0,0 +1,63 @@ +# Matter Android Virtual Device App Example + +This is a Matter Android Device app that can be used as a commissionee device. + +This app offers the following features: + +- Work as a commissionee device on Android environment +- Make custom payload information and display Matter QR code +- Provide UI for the user to change the cluster attribute values and create + the cluster event + +


+ +- [Matter Android Virtual Device App Example](#matter-android-virtual-device-app-example) + - [Requirements for building](#requirements-for-building) + - [Preparing for build](#preparing-for-build) + - [Building & Installing the app](#building--installing-the-app) + +
+ + + +## Requirements for building + +For information about how to build the application, see the +[Building Android](../../../docs/guides/android_building.md) guide. + +## Preparing for build + +Complete the following steps to prepare the Matter build: + +1. Check out the Matter repository. + +2. Run bootstrap (**only required first time**) + + ```shell + source scripts/bootstrap.sh + ``` + + + +## Building & Installing the app + +This is the simplest option. In the command line, run the following command from +the top Matter directory: + +```shell +./scripts/build/build_examples.py --target android-arm64-virtual-device-app build +``` + +See the table above for other values of `TARGET_CPU`. + +The debug Android package `app-debug.apk` will be generated at +`out/android-$TARGET_CPU-virtual-device-app/VirtualDeviceApp/app/outputs/apk/debug/`, +and can be installed with + +```shell +adb install out/android-$TARGET_CPU-virtual-device-app/VirtualDeviceApp/app/outputs/apk/debug/app-debug.apk +``` + +You can use Android Studio to edit the Android app itself and run it after +build_examples.py, but you will not be able to edit Matter Android code from +`src/controller/java`, or other Matter C++ code within Android Studio. diff --git a/examples/virtual-device-app/android/args.gni b/examples/virtual-device-app/android/args.gni new file mode 100644 index 00000000000000..392915e9c71fc9 --- /dev/null +++ b/examples/virtual-device-app/android/args.gni @@ -0,0 +1,27 @@ +# 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. + +import("//build_overrides/chip.gni") + +import("${chip_root}/config/standalone/args.gni") + +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_system_project_config_include = "" + +chip_project_config_include_dirs = + [ "${chip_root}/examples/virtual-device-app/virtual-device-common/include" ] +chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ] + +chip_config_network_layer_ble = true diff --git a/examples/virtual-device-app/android/build_overrides b/examples/virtual-device-app/android/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/virtual-device-app/android/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/virtual-device-app/android/java/AppImpl.cpp b/examples/virtual-device-app/android/java/AppImpl.cpp new file mode 100644 index 00000000000000..34543d4bb526f8 --- /dev/null +++ b/examples/virtual-device-app/android/java/AppImpl.cpp @@ -0,0 +1,103 @@ +/* + * + * 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. + */ + +#include "AppImpl.h" +#include "DeviceApp-JNI.h" + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::DeviceLayer; + +void DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + ChipLogProgress(DeviceLayer, "DeviceEventCallback : %d", event->Type); + + switch (event->Type) + { + case DeviceEventType::kWiFiConnectivityChange: + ChipLogProgress(DeviceLayer, "kWiFiConnectivityChange"); + break; + case DeviceEventType::kInternetConnectivityChange: + ChipLogProgress(DeviceLayer, "InternetConnectivityChange"); + break; + case DeviceEventType::kServiceConnectivityChange: + ChipLogProgress(DeviceLayer, "ServiceConnectivityChange"); + break; + case DeviceEventType::kServiceProvisioningChange: + ChipLogProgress(DeviceLayer, "ServiceProvisioningChange"); + break; + case DeviceEventType::kCHIPoBLEConnectionEstablished: + ChipLogProgress(DeviceLayer, "CHIPoBLE connection established"); + break; + case DeviceEventType::kCHIPoBLEConnectionClosed: + ChipLogProgress(DeviceLayer, "CHIPoBLE disconnected"); + break; + case DeviceEventType::kCHIPoBLEAdvertisingChange: + ChipLogProgress(DeviceLayer, "CHIPoBLEAdvertisingChange"); + break; + case DeviceEventType::kInterfaceIpAddressChanged: + ChipLogProgress(DeviceLayer, "InterfaceIpAddressChanged"); + break; + case DeviceEventType::kCommissioningComplete: + ChipLogProgress(DeviceLayer, "Commissioning complete"); + break; + case DeviceEventType::kOperationalNetworkEnabled: + ChipLogProgress(DeviceLayer, "OperationalNetworkEnabled"); + break; + case DeviceEventType::kDnssdInitialized: + ChipLogProgress(DeviceLayer, "DnssdPlatformInitialized"); + break; + } + + DeviceAppJNIMgr().PostEvent(event->Type); +} + +static int kFabricRemoved = 0x9FFF; // out of public event range (0x8000) + +class FabricDelegate : public FabricTable::Delegate +{ + void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override + { + ChipLogProgress(DeviceLayer, "OnFabricRemoved():FabricCount[%d],FabricIndex[%d]", fabricTable.FabricCount(), fabricIndex); + if (fabricTable.FabricCount() == 0) + { + DeviceAppJNIMgr().PostEvent(kFabricRemoved); + } + } +}; + +static FabricDelegate gFabricDelegate; + +CHIP_ERROR PreServerInit() +{ + /** + * Apply any user-defined configurations prior to initializing Server. + * + * Ex. + * DnssdServer::Instance().SetExtendedDiscoveryTimeoutSecs(userTimeoutSecs); + * + */ + + chip::DeviceLayer::PlatformMgr().AddEventHandler(DeviceEventCallback, reinterpret_cast(nullptr)); + Server::GetInstance().GetFabricTable().AddFabricDelegate(&gFabricDelegate); + + return CHIP_NO_ERROR; +} diff --git a/examples/virtual-device-app/android/java/AppImpl.h b/examples/virtual-device-app/android/java/AppImpl.h new file mode 100644 index 00000000000000..9ac6ae1037f9f6 --- /dev/null +++ b/examples/virtual-device-app/android/java/AppImpl.h @@ -0,0 +1,23 @@ +/* + * + * 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 + +CHIP_ERROR PreServerInit(); diff --git a/examples/virtual-device-app/android/java/ClusterChangeAttribute.cpp b/examples/virtual-device-app/android/java/ClusterChangeAttribute.cpp new file mode 100644 index 00000000000000..be16005ff089a1 --- /dev/null +++ b/examples/virtual-device-app/android/java/ClusterChangeAttribute.cpp @@ -0,0 +1,56 @@ +/* + * + * 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 "OnOffManager.h" +#include +#include +#include +#include +#include + +using namespace chip; +using namespace ::chip::app::Clusters; + +static void OnOffClusterAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint16_t size, uint8_t * value) +{ + if (attributePath.mAttributeId == OnOff::Attributes::OnOff::Id) + { + bool onoff = static_cast(*value); + + ChipLogProgress(Zcl, "Received on/off command endpoint %d value = %d", static_cast(attributePath.mEndpointId), onoff); + + OnOffManager().PostOnOffChanged(attributePath.mEndpointId, onoff); + } +} + +void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) +{ + ChipLogProgress(Zcl, "[Device] clusterId:%d,attributeId:%d,endpoint:%d", attributePath.mClusterId, attributePath.mAttributeId, + static_cast(attributePath.mEndpointId)); + + switch (attributePath.mClusterId) + { + case OnOff::Id: + OnOffClusterAttributeChangeCallback(attributePath, size, value); + break; + + default: + break; + } +} diff --git a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp new file mode 100644 index 00000000000000..1f1b918b6d1aee --- /dev/null +++ b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp @@ -0,0 +1,159 @@ +/* + * 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 "DeviceApp-JNI.h" +#include "AppImpl.h" +#include "JNIDACProvider.h" + +#include "OnOffManager.h" +#include "credentials/DeviceAttestationCredsProvider.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::AppPlatform; +using namespace chip::Credentials; +using namespace chip::DeviceLayer; + +#define JNI_METHOD(RETURN, METHOD_NAME) \ + extern "C" JNIEXPORT RETURN JNICALL Java_com_matter_virtual_device_app_DeviceApp_##METHOD_NAME + +#define DEVICE_VERSION_DEFAULT 1 + +EmberAfDeviceType gDeviceTypeIds[] = { { 0, DEVICE_VERSION_DEFAULT } }; +DeviceAppJNI DeviceAppJNI::sInstance; + +void DeviceAppJNI::InitializeWithObjects(jobject app) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for DeviceAppJNI")); + + mDeviceAppObject = env->NewGlobalRef(app); + VerifyOrReturn(mDeviceAppObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef DeviceAppJNI")); + + jclass managerClass = env->GetObjectClass(mDeviceAppObject); + VerifyOrReturn(managerClass != nullptr, ChipLogError(Zcl, "Failed to get DeviceAppJNI Java class")); + + mPostClusterInitMethod = env->GetMethodID(managerClass, "postClusterInit", "(II)V"); + if (mPostClusterInitMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access DeviceApp 'postClusterInit' method"); + env->ExceptionClear(); + } + + mPostEventMethod = env->GetMethodID(managerClass, "postEvent", "(I)V"); + if (mPostEventMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access DeviceApp 'postEvent' method"); + env->ExceptionClear(); + } +} + +void DeviceAppJNI::PostClusterInit(int clusterId, int endpoint) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for DeviceAppJNI::PostClusterInit")); + VerifyOrReturn(mDeviceAppObject != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mDeviceAppObject null")); + VerifyOrReturn(mPostClusterInitMethod != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mPostClusterInitMethod null")); + + env->CallVoidMethod(mDeviceAppObject, mPostClusterInitMethod, static_cast(clusterId), static_cast(endpoint)); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Failed to call DeviceAppJNI 'postClusterInit' method"); + env->ExceptionClear(); + } +} + +void DeviceAppJNI::PostEvent(int event) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for DeviceAppJNI::PostEvent")); + VerifyOrReturn(mDeviceAppObject != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mDeviceAppObject null")); + VerifyOrReturn(mPostEventMethod != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mPostEventMethod null")); + + env->CallVoidMethod(mDeviceAppObject, mPostEventMethod, static_cast(event)); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Failed to call DeviceAppJNI 'postEventMethod' method"); + env->ExceptionClear(); + } +} + +jint JNI_OnLoad(JavaVM * jvm, void * reserved) +{ + return AndroidAppServerJNI_OnLoad(jvm, reserved); +} + +void JNI_OnUnload(JavaVM * jvm, void * reserved) +{ + return AndroidAppServerJNI_OnUnload(jvm, reserved); +} + +JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app) +{ + DeviceAppJNIMgr().InitializeWithObjects(app); +} + +JNI_METHOD(void, preServerInit)(JNIEnv *, jobject app) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(Zcl, "DeviceAppJNI::preServerInit"); + + PreServerInit(); +} + +JNI_METHOD(void, postServerInit)(JNIEnv *, jobject app, jint deviceTypeId) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(Zcl, "DeviceAppJNI::postServerInit"); + + gDeviceTypeIds[0].deviceId = static_cast(deviceTypeId); + emberAfSetDeviceTypeList(1, Span(gDeviceTypeIds)); +} + +JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) +{ + if (!chip::Credentials::IsDeviceAttestationCredentialsProviderSet()) + { + JNIDACProvider * p = new JNIDACProvider(provider); + chip::Credentials::SetDeviceAttestationCredentialsProvider(p); + } +} + +/* + * On Off Manager + */ +JNI_METHOD(void, setOnOffManager)(JNIEnv *, jobject, jint endpoint, jobject manager) +{ + OnOffManager::NewManager(endpoint, manager); +} + +JNI_METHOD(jboolean, setOnOff)(JNIEnv *, jobject, jint endpoint, jboolean value) +{ + return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { OnOffManager::SetOnOff(endpoint, value); }) == + CHIP_NO_ERROR; +} diff --git a/examples/virtual-device-app/android/java/DeviceApp-JNI.h b/examples/virtual-device-app/android/java/DeviceApp-JNI.h new file mode 100644 index 00000000000000..e6772a41b16902 --- /dev/null +++ b/examples/virtual-device-app/android/java/DeviceApp-JNI.h @@ -0,0 +1,42 @@ +/* + * + * 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 + +class DeviceAppJNI +{ +public: + void InitializeWithObjects(jobject app); + void PostClusterInit(int clusterId, int endpoint); + void PostEvent(int event); + +private: + friend DeviceAppJNI & DeviceAppJNIMgr(); + + static DeviceAppJNI sInstance; + jobject mDeviceAppObject = nullptr; + jmethodID mPostClusterInitMethod = nullptr; + jmethodID mPostEventMethod = nullptr; +}; + +inline class DeviceAppJNI & DeviceAppJNIMgr() +{ + return DeviceAppJNI::sInstance; +} diff --git a/examples/virtual-device-app/android/java/JNIDACProvider.cpp b/examples/virtual-device-app/android/java/JNIDACProvider.cpp new file mode 100644 index 00000000000000..2b3f72e8c7e85b --- /dev/null +++ b/examples/virtual-device-app/android/java/JNIDACProvider.cpp @@ -0,0 +1,172 @@ +/* + * + * 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. + */ + +#include "JNIDACProvider.h" +#include "lib/support/logging/CHIPLogging.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; + +JNIDACProvider::JNIDACProvider(jobject provider) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for JNIDACProvider")); + + mJNIDACProviderObject = env->NewGlobalRef(provider); + VerifyOrReturn(mJNIDACProviderObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef JNIDACProvider")); + + jclass JNIDACProviderClass = env->GetObjectClass(provider); + VerifyOrReturn(JNIDACProviderClass != nullptr, ChipLogError(Zcl, "Failed to get JNIDACProvider Java class")); + + mGetCertificationDeclarationMethod = env->GetMethodID(JNIDACProviderClass, "GetCertificationDeclaration", "()[B"); + if (mGetCertificationDeclarationMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetCertificationDeclaration' method"); + env->ExceptionClear(); + } + + mGetFirmwareInformationMethod = env->GetMethodID(JNIDACProviderClass, "GetFirmwareInformation", "()[B"); + if (mGetFirmwareInformationMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetFirmwareInformation' method"); + env->ExceptionClear(); + } + + mGetDeviceAttestationCertMethod = env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCert", "()[B"); + if (mGetDeviceAttestationCertMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCert' method"); + env->ExceptionClear(); + } + + mGetProductAttestationIntermediateCertMethod = + env->GetMethodID(JNIDACProviderClass, "GetProductAttestationIntermediateCert", "()[B"); + if (mGetProductAttestationIntermediateCertMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetProductAttestationIntermediateCert' method"); + env->ExceptionClear(); + } + + mGetDeviceAttestationCertPrivateKeyMethod = env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCertPrivateKey", "()[B"); + if (mGetDeviceAttestationCertPrivateKeyMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCertPrivateKey' method"); + env->ExceptionClear(); + } + + mGetDeviceAttestationCertPublicKeyKeyMethod = + env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCertPublicKeyKey", "()[B"); + if (mGetDeviceAttestationCertPublicKeyKeyMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCertPublicKeyKey' method"); + env->ExceptionClear(); + } +} + +CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan & out_buffer) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnLogError(mJNIDACProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(method != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); + + jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Java exception in get Method"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + if (outArray == nullptr || env->GetArrayLength(outArray) <= 0) + { + out_buffer.reduce_size(0); + return CHIP_NO_ERROR; + } + + JniByteArray JniOutArray(env, outArray); + return CopySpanToMutableSpan(JniOutArray.byteSpan(), out_buffer); +} + +CHIP_ERROR JNIDACProvider::GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) +{ + ChipLogProgress(Zcl, "Received GetCertificationDeclaration"); + return GetJavaByteByMethod(mGetCertificationDeclarationMethod, out_cd_buffer); +} + +CHIP_ERROR JNIDACProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + ChipLogProgress(Zcl, "Received GetFirmwareInformation"); + return GetJavaByteByMethod(mGetFirmwareInformationMethod, out_firmware_info_buffer); +} + +CHIP_ERROR JNIDACProvider::GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) +{ + ChipLogProgress(Zcl, "Received GetDeviceAttestationCert"); + return GetJavaByteByMethod(mGetDeviceAttestationCertMethod, out_dac_buffer); +} + +CHIP_ERROR JNIDACProvider::GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) +{ + ChipLogProgress(Zcl, "Received GetProductAttestationIntermediateCert"); + return GetJavaByteByMethod(mGetProductAttestationIntermediateCertMethod, out_pai_buffer); +} + +// TODO: This should be moved to a method of P256Keypair +CHIP_ERROR LoadKeypairFromRaw(ByteSpan private_key, ByteSpan public_key, Crypto::P256Keypair & keypair) +{ + Crypto::P256SerializedKeypair serialized_keypair; + ReturnErrorOnFailure(serialized_keypair.SetLength(private_key.size() + public_key.size())); + memcpy(serialized_keypair.Bytes(), public_key.data(), public_key.size()); + memcpy(serialized_keypair.Bytes() + public_key.size(), private_key.data(), private_key.size()); + return keypair.Deserialize(serialized_keypair); +} + +CHIP_ERROR JNIDACProvider::SignWithDeviceAttestationKey(const ByteSpan & digest_to_sign, MutableByteSpan & out_signature_buffer) +{ + ChipLogProgress(Zcl, "Received SignWithDeviceAttestationKey"); + Crypto::P256ECDSASignature signature; + Crypto::P256Keypair keypair; + + VerifyOrReturnError(IsSpanUsable(out_signature_buffer), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsSpanUsable(digest_to_sign), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_signature_buffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint8_t privateKeyBuf[Crypto::kP256_PrivateKey_Length]; + MutableByteSpan privateKeyBufSpan(privateKeyBuf); + ReturnErrorOnFailure(GetJavaByteByMethod(mGetDeviceAttestationCertPrivateKeyMethod, privateKeyBufSpan)); + + uint8_t publicKeyBuf[Crypto::kP256_PublicKey_Length]; + MutableByteSpan publicKeyBufSpan(publicKeyBuf); + ReturnErrorOnFailure(GetJavaByteByMethod(mGetDeviceAttestationCertPublicKeyKeyMethod, publicKeyBufSpan)); + + // In a non-exemplary implementation, the public key is not needed here. It is used here merely because + // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. + ReturnErrorOnFailure(LoadKeypairFromRaw(privateKeyBufSpan, publicKeyBufSpan, keypair)); + ReturnErrorOnFailure(keypair.ECDSA_sign_msg(digest_to_sign.data(), digest_to_sign.size(), signature)); + + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, out_signature_buffer); +} diff --git a/examples/virtual-device-app/android/java/JNIDACProvider.h b/examples/virtual-device-app/android/java/JNIDACProvider.h new file mode 100644 index 00000000000000..e2bad80e226f9f --- /dev/null +++ b/examples/virtual-device-app/android/java/JNIDACProvider.h @@ -0,0 +1,43 @@ +/* + * + * 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. + */ +#pragma once + +#include "lib/support/logging/CHIPLogging.h" +#include +#include + +class JNIDACProvider : public chip::Credentials::DeviceAttestationCredentialsProvider +{ +public: + JNIDACProvider(jobject provider); + CHIP_ERROR GetCertificationDeclaration(chip::MutableByteSpan & out_cd_buffer) override; + CHIP_ERROR GetFirmwareInformation(chip::MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(chip::MutableByteSpan & out_dac_buffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(chip::MutableByteSpan & out_pai_buffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const chip::ByteSpan & digest_to_sign, + chip::MutableByteSpan & out_signature_buffer) override; + +private: + CHIP_ERROR GetJavaByteByMethod(jmethodID method, chip::MutableByteSpan & out_buffer); + jobject mJNIDACProviderObject = nullptr; + jmethodID mGetCertificationDeclarationMethod = nullptr; + jmethodID mGetFirmwareInformationMethod = nullptr; + jmethodID mGetDeviceAttestationCertMethod = nullptr; + jmethodID mGetProductAttestationIntermediateCertMethod = nullptr; + jmethodID mGetDeviceAttestationCertPrivateKeyMethod = nullptr; + jmethodID mGetDeviceAttestationCertPublicKeyKeyMethod = nullptr; +}; diff --git a/examples/virtual-device-app/android/java/OnOffManager.cpp b/examples/virtual-device-app/android/java/OnOffManager.cpp new file mode 100644 index 00000000000000..09d5265df8ab09 --- /dev/null +++ b/examples/virtual-device-app/android/java/OnOffManager.cpp @@ -0,0 +1,128 @@ +/** + * + * 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. + */ +#include "OnOffManager.h" +#include "DeviceApp-JNI.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; + +static constexpr size_t kOnffManagerTableSize = EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT; + +namespace { + +OnOffManager * gOnOffManagerTable[kOnffManagerTableSize] = { nullptr }; +static_assert(kOnffManagerTableSize <= kEmberInvalidEndpointIndex, "gOnOffManagerTable table size error"); + +} // namespace + +void emberAfOnOffClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "Device App::OnOff::PostClusterInit"); + DeviceAppJNIMgr().PostClusterInit(chip::app::Clusters::OnOff::Id, endpoint); +} + +void OnOffManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "Device App: OnOffManager::NewManager"); + uint16_t ep = emberAfGetClusterServerEndpointIndex(static_cast(endpoint), app::Clusters::OnOff::Id, + EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT); + VerifyOrReturn(ep < kOnffManagerTableSize, ChipLogError(Zcl, "Device App::OnOff::NewManager: endpoint %d not found", endpoint)); + + VerifyOrReturn(gOnOffManagerTable[ep] == nullptr, + ChipLogError(Zcl, "Device App::OnOff::NewManager: endpoint %d already has a manager", endpoint)); + OnOffManager * mgr = new OnOffManager(); + CHIP_ERROR err = mgr->InitializeWithObjects(manager); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Device App::OnOff::NewManager: failed to initialize manager for endpoint %d", endpoint); + delete mgr; + } + else + { + gOnOffManagerTable[ep] = mgr; + } +} + +OnOffManager * GetOnOffManager(EndpointId endpoint) +{ + uint16_t ep = + emberAfGetClusterServerEndpointIndex(endpoint, app::Clusters::OnOff::Id, EMBER_AF_ON_OFF_CLUSTER_SERVER_ENDPOINT_COUNT); + return (ep >= kOnffManagerTableSize ? nullptr : gOnOffManagerTable[ep]); +} + +void OnOffManager::PostOnOffChanged(chip::EndpointId endpoint, bool value) +{ + ChipLogProgress(Zcl, "Device App: OnOffManager::PostOnOffChange"); + OnOffManager * mgr = GetOnOffManager(endpoint); + VerifyOrReturn(mgr != nullptr, ChipLogError(Zcl, "OnOffManager null")); + + mgr->HandleOnOffChanged(value); +} + +jboolean OnOffManager::SetOnOff(jint endpoint, bool value) +{ + EmberAfStatus status = app::Clusters::OnOff::Attributes::OnOff::Set(static_cast(endpoint), value); + return status == EMBER_ZCL_STATUS_SUCCESS; +} + +CHIP_ERROR OnOffManager::InitializeWithObjects(jobject managerObject) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnLogError(env != nullptr, CHIP_ERROR_INCORRECT_STATE); + + mOnOffManagerObject = env->NewGlobalRef(managerObject); + VerifyOrReturnLogError(mOnOffManagerObject != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + jclass OnOffManagerClass = env->GetObjectClass(managerObject); + VerifyOrReturnLogError(OnOffManagerClass != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + mHandleOnOffChangedMethod = env->GetMethodID(OnOffManagerClass, "HandleOnOffChanged", "(Z)V"); + if (mHandleOnOffChangedMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access OnOffManager 'HandleOnOffChanged' method"); + env->ExceptionClear(); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + return CHIP_NO_ERROR; +} + +void OnOffManager::HandleOnOffChanged(bool value) +{ + ChipLogProgress(Zcl, "OnOffManager::HandleOnOffChanged"); + + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != NULL, ChipLogProgress(Zcl, "env null")); + VerifyOrReturn(mOnOffManagerObject != nullptr, ChipLogProgress(Zcl, "mOnOffManagerObject null")); + VerifyOrReturn(mHandleOnOffChangedMethod != nullptr, ChipLogProgress(Zcl, "mHandleOnOffChangedMethod null")); + + env->ExceptionClear(); + env->CallVoidMethod(mOnOffManagerObject, mHandleOnOffChangedMethod, static_cast(value)); + if (env->ExceptionCheck()) + { + ChipLogError(AppServer, "Java exception in OnOffManager::HandleOnOffChanged"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} diff --git a/examples/virtual-device-app/android/java/OnOffManager.h b/examples/virtual-device-app/android/java/OnOffManager.h new file mode 100644 index 00000000000000..7305d10c46b22e --- /dev/null +++ b/examples/virtual-device-app/android/java/OnOffManager.h @@ -0,0 +1,45 @@ +/* + * + * 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. + */ +#pragma once + +#include +#include + +/** + * @brief Handles interfacing between java code and C++ code for the purposes of On/Off clusters. + */ +class OnOffManager +{ +public: + // installed a bridege for a On/Off cluster endpoint and java object + static void NewManager(jint endpoint, jobject manager); + + // helps for java to set attributes::OnOff of OnOff cluster + static jboolean SetOnOff(jint endpoint, bool value); + + // posts a OnOffChanged event to suitable OnOffManager + static void PostOnOffChanged(chip::EndpointId endpoint, bool value); + + // handles `Changed` callbacks by calling the java `void HandleOnOffChanged()` method + void HandleOnOffChanged(bool value); + +private: + // init with java objects + CHIP_ERROR InitializeWithObjects(jobject managerObject); + jobject mOnOffManagerObject = nullptr; + jmethodID mHandleOnOffChangedMethod = nullptr; +}; diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DACProvider.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DACProvider.java new file mode 100644 index 00000000000000..5113f99a806509 --- /dev/null +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DACProvider.java @@ -0,0 +1,32 @@ +/* + * 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. + * + */ +package com.matter.virtual.device.app; + +public interface DACProvider { + byte[] GetCertificationDeclaration(); + + byte[] GetFirmwareInformation(); + + byte[] GetDeviceAttestationCert(); + + byte[] GetProductAttestationIntermediateCert(); + + byte[] GetDeviceAttestationCertPrivateKey(); + + byte[] GetDeviceAttestationCertPublicKeyKey(); +} diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java new file mode 100644 index 00000000000000..6d86374cdf7b0c --- /dev/null +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java @@ -0,0 +1,62 @@ +/* + * 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. + * + */ +package com.matter.virtual.device.app; + +import android.util.Log; + +public class DeviceApp { + private DeviceAppCallback mCallback; + private static final String TAG = "DeviceApp"; + + public DeviceApp(DeviceAppCallback callback) { + mCallback = callback; + nativeInit(); + } + + private void postClusterInit(int clusterId, int endpoint) { + Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); + if (mCallback != null) { + mCallback.onClusterInit(this, clusterId, endpoint); + } + } + + private void postEvent(int event) { + Log.d(TAG, "postEvent : " + event); + if (mCallback != null) { + mCallback.onEvent(event); + } + } + + public native void nativeInit(); + + // called before Matter server is initiated + public native void preServerInit(); + + // called after Matter server is initiated + public native void postServerInit(int deviceTypeId); + + public native void setOnOffManager(int endpoint, OnOffManager manager); + + public native boolean setOnOff(int endpoint, boolean value); + + public native void setDACProvider(DACProvider provider); + + static { + System.loadLibrary("DeviceApp"); + } +} diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java new file mode 100644 index 00000000000000..d0cb46a341d448 --- /dev/null +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java @@ -0,0 +1,23 @@ +/* + * + * 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 com.matter.virtual.device.app; + +public interface DeviceAppCallback { + void onClusterInit(DeviceApp app, int clusterId, int endpoint); + + void onEvent(int event); +} diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java new file mode 100644 index 00000000000000..d6ec0f2d56d543 --- /dev/null +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java @@ -0,0 +1,11 @@ +package com.matter.virtual.device.app; + +public interface OnOffManager { + /** + * Notify that the OnOff value be changed by matter and should effect it. Note, set by TvApp will + * also trigger this function, so must check if value is same + * + * @param value + */ + void HandleOnOffChanged(boolean value); +} diff --git a/examples/virtual-device-app/android/third_party/connectedhomeip b/examples/virtual-device-app/android/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/virtual-device-app/android/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/virtual-device-app/virtual-device-common/BUILD.gn b/examples/virtual-device-app/virtual-device-common/BUILD.gn new file mode 100644 index 00000000000000..73be6ac9628be1 --- /dev/null +++ b/examples/virtual-device-app/virtual-device-common/BUILD.gn @@ -0,0 +1,26 @@ +# 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. + +import("//build_overrides/chip.gni") + +import("${chip_root}/src/app/chip_data_model.gni") +import("${chip_root}/src/lib/lib.gni") + +chip_data_model("virtual-device-common") { + zap_file = "virtual-device-app.zap" + + zap_pregenerated_dir = + "${chip_root}/zzz_generated/virtual-device-app/zap-generated" + is_server = true +} diff --git a/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h b/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h new file mode 100644 index 00000000000000..baaeab39b590dc --- /dev/null +++ b/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h @@ -0,0 +1,52 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 0 + +#define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART 1 + +// Enable extended discovery, set timeout to 24 hours +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 0 +#define CHIP_DEVICE_CONFIG_EXTENDED_DISCOVERY_TIMEOUT_SECS (24 * 60 * 60) + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1 + +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1 +#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Matter Device" + +// Enable app platform +#define CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED 0 + +// overrides CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT in CHIPProjectConfig +#define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT 16 + +// include the CHIPProjectConfig from config/standalone +#include diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter new file mode 100644 index 00000000000000..d86ccf415c13aa --- /dev/null +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter @@ -0,0 +1,1925 @@ +// This IDL was generated automatically by ZAP. +// It is for view/code review purposes only. + +struct ModeTagStruct { + optional vendor_id mfgCode = 0; + enum16 value = 1; +} + +struct ModeOptionStruct { + char_string<64> label = 0; + int8u mode = 1; + ModeTagStruct modeTags[] = 2; +} + +struct ApplicationStruct { + int16u catalogVendorID = 0; + char_string applicationID = 1; +} + +struct ErrorStateStruct { + enum8 errorStateID = 0; + optional char_string<64> errorStateLabel = 1; + optional char_string<64> errorStateDetails = 2; +} + +struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; +} + +struct OperationalStateStruct { + enum8 operationalStateID = 0; + optional char_string<64> operationalStateLabel = 1; +} + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +server cluster Identify = 3 { + enum EffectIdentifierEnum : ENUM8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : ENUM8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : ENUM8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + 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 IdentifyRequest { + INT16U identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** Attributes and commands for group configuration and manipulation. */ +server cluster Groups = 4 { + bitmap Feature : BITMAP32 { + kGroupNames = 0x1; + } + + bitmap NameSupportBitmap : BITMAP8 { + kGroupNames = 0x80; + } + + readonly attribute NameSupportBitmap nameSupport = 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 AddGroupRequest { + group_id groupID = 0; + CHAR_STRING groupName = 1; + } + + request struct ViewGroupRequest { + group_id groupID = 0; + } + + request struct GetGroupMembershipRequest { + group_id groupList[] = 0; + } + + request struct RemoveGroupRequest { + group_id groupID = 0; + } + + request struct AddGroupIfIdentifyingRequest { + group_id groupID = 0; + CHAR_STRING groupName = 1; + } + + response struct AddGroupResponse = 0 { + ENUM8 status = 0; + group_id groupID = 1; + } + + response struct ViewGroupResponse = 1 { + ENUM8 status = 0; + group_id groupID = 1; + CHAR_STRING groupName = 2; + } + + response struct GetGroupMembershipResponse = 2 { + nullable INT8U capacity = 0; + group_id groupList[] = 1; + } + + response struct RemoveGroupResponse = 3 { + ENUM8 status = 0; + group_id groupID = 1; + } + + fabric command access(invoke: manage) AddGroup(AddGroupRequest): AddGroupResponse = 0; + fabric command ViewGroup(ViewGroupRequest): ViewGroupResponse = 1; + fabric command GetGroupMembership(GetGroupMembershipRequest): GetGroupMembershipResponse = 2; + fabric command access(invoke: manage) RemoveGroup(RemoveGroupRequest): RemoveGroupResponse = 3; + fabric command access(invoke: manage) RemoveAllGroups(): DefaultSuccess = 4; + fabric command access(invoke: manage) AddGroupIfIdentifying(AddGroupIfIdentifyingRequest): DefaultSuccess = 5; +} + +/** Attributes and commands for scene configuration and manipulation. */ +server cluster Scenes = 5 { + bitmap Feature : BITMAP32 { + kSceneNames = 0x1; + } + + bitmap ScenesCopyMode : BITMAP8 { + kCopyAllScenes = 0x1; + } + + struct AttributeValuePair { + attrib_id attributeID = 0; + int32u attributeValue = 1; + } + + struct ExtensionFieldSet { + cluster_id clusterID = 0; + AttributeValuePair attributeValueList[] = 1; + } + + readonly attribute int8u sceneCount = 0; + readonly attribute int8u currentScene = 1; + readonly attribute group_id currentGroup = 2; + readonly attribute boolean sceneValid = 3; + readonly attribute bitmap8 nameSupport = 4; + readonly attribute int16u sceneTableSize = 6; + readonly attribute int8u remainingCapacity = 7; + 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 AddSceneRequest { + group_id groupID = 0; + INT8U sceneID = 1; + INT16U transitionTime = 2; + CHAR_STRING sceneName = 3; + ExtensionFieldSet extensionFieldSets[] = 4; + } + + request struct ViewSceneRequest { + group_id groupID = 0; + INT8U sceneID = 1; + } + + request struct RemoveSceneRequest { + group_id groupID = 0; + INT8U sceneID = 1; + } + + request struct RemoveAllScenesRequest { + group_id groupID = 0; + } + + request struct StoreSceneRequest { + group_id groupID = 0; + INT8U sceneID = 1; + } + + request struct RecallSceneRequest { + group_id groupID = 0; + INT8U sceneID = 1; + optional nullable INT16U transitionTime = 2; + } + + request struct GetSceneMembershipRequest { + group_id groupID = 0; + } + + response struct AddSceneResponse = 0 { + status status = 0; + group_id groupID = 1; + INT8U sceneID = 2; + } + + response struct ViewSceneResponse = 1 { + status status = 0; + group_id groupID = 1; + INT8U sceneID = 2; + optional INT16U transitionTime = 3; + optional CHAR_STRING sceneName = 4; + optional ExtensionFieldSet extensionFieldSets[] = 5; + } + + response struct RemoveSceneResponse = 2 { + status status = 0; + group_id groupID = 1; + INT8U sceneID = 2; + } + + response struct RemoveAllScenesResponse = 3 { + status status = 0; + group_id groupID = 1; + } + + response struct StoreSceneResponse = 4 { + status status = 0; + group_id groupID = 1; + INT8U sceneID = 2; + } + + response struct GetSceneMembershipResponse = 6 { + status status = 0; + nullable INT8U capacity = 1; + group_id groupID = 2; + optional INT8U sceneList[] = 3; + } + + fabric command access(invoke: manage) AddScene(AddSceneRequest): AddSceneResponse = 0; + fabric command ViewScene(ViewSceneRequest): ViewSceneResponse = 1; + fabric command access(invoke: manage) RemoveScene(RemoveSceneRequest): RemoveSceneResponse = 2; + fabric command access(invoke: manage) RemoveAllScenes(RemoveAllScenesRequest): RemoveAllScenesResponse = 3; + fabric command access(invoke: manage) StoreScene(StoreSceneRequest): StoreSceneResponse = 4; + fabric command RecallScene(RecallSceneRequest): DefaultSuccess = 5; + fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; +} + +/** Attributes and commands for switching devices between 'On' and 'Off' states. */ +server cluster OnOff = 6 { + enum OnOffDelayedAllOffEffectVariant : ENUM8 { + kFadeToOffIn0p8Seconds = 0; + kNoFade = 1; + k50PercentDimDownIn0p8SecondsThenFadeToOffIn12Seconds = 2; + } + + enum OnOffDyingLightEffectVariant : ENUM8 { + k20PercenterDimUpIn0p5SecondsThenFadeToOffIn1Second = 0; + } + + enum OnOffEffectIdentifier : ENUM8 { + kDelayedAllOff = 0; + kDyingLight = 1; + } + + enum OnOffStartUpOnOff : ENUM8 { + kOff = 0; + kOn = 1; + kTogglePreviousOnOff = 2; + } + + bitmap Feature : BITMAP32 { + kLighting = 0x1; + kDeadFront = 0x2; + } + + bitmap OnOffControl : BITMAP8 { + kAcceptOnlyWhenOn = 0x1; + } + + readonly nosubscribe attribute boolean onOff = 0; + readonly attribute boolean globalSceneControl = 16384; + attribute int16u onTime = 16385; + attribute int16u offWaitTime = 16386; + attribute access(write: manage) nullable OnOffStartUpOnOff startUpOnOff = 16387; + 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 OffWithEffectRequest { + OnOffEffectIdentifier effectIdentifier = 0; + int8u effectVariant = 1; + } + + request struct OnWithTimedOffRequest { + OnOffControl onOffControl = 0; + int16u onTime = 1; + int16u offWaitTime = 2; + } + + command Off(): DefaultSuccess = 0; + command On(): DefaultSuccess = 1; + command Toggle(): DefaultSuccess = 2; + command OffWithEffect(OffWithEffectRequest): DefaultSuccess = 64; + command OnWithRecallGlobalScene(): DefaultSuccess = 65; + command OnWithTimedOff(OnWithTimedOffRequest): DefaultSuccess = 66; +} + +/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ +server cluster Descriptor = 29 { + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + readonly attribute DeviceTypeStruct deviceTypeList[] = 0; + readonly attribute CLUSTER_ID serverList[] = 1; + readonly attribute CLUSTER_ID clientList[] = 2; + readonly attribute ENDPOINT_NO partsList[] = 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; +} + +/** The Binding Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for supporting the binding table. */ +server cluster Binding = 30 { + fabric_scoped struct TargetStruct { + optional node_id node = 1; + optional group_id group = 2; + optional endpoint_no endpoint = 3; + optional cluster_id cluster = 4; + fabric_idx fabricIndex = 254; + } + + attribute TargetStruct binding[] = 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; +} + +/** The Access Control Cluster exposes a data model view of a + Node's Access Control List (ACL), which codifies the rules used to manage + and enforce Access Control for the Node's endpoints and their associated + cluster instances. */ +server cluster AccessControl = 31 { + enum AccessControlEntryAuthModeEnum : ENUM8 { + kPASE = 1; + kCASE = 2; + kGroup = 3; + } + + enum AccessControlEntryPrivilegeEnum : ENUM8 { + kView = 1; + kProxyView = 2; + kOperate = 3; + kManage = 4; + kAdminister = 5; + } + + enum ChangeTypeEnum : ENUM8 { + kChanged = 0; + kAdded = 1; + kRemoved = 2; + } + + struct AccessControlTargetStruct { + nullable cluster_id cluster = 0; + nullable endpoint_no endpoint = 1; + nullable devtype_id deviceType = 2; + } + + fabric_scoped struct AccessControlEntryStruct { + fabric_sensitive AccessControlEntryPrivilegeEnum privilege = 1; + fabric_sensitive AccessControlEntryAuthModeEnum authMode = 2; + nullable fabric_sensitive int64u subjects[] = 3; + nullable fabric_sensitive AccessControlTargetStruct targets[] = 4; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct AccessControlExtensionStruct { + fabric_sensitive octet_string<128> data = 1; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlEntryChanged = 0 { + nullable node_id adminNodeID = 1; + nullable INT16U adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlEntryStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlExtensionChanged = 1 { + nullable node_id adminNodeID = 1; + nullable INT16U adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlExtensionStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + attribute access(read: administer, write: administer) AccessControlEntryStruct acl[] = 0; + attribute access(read: administer, write: administer) AccessControlExtensionStruct extension[] = 1; + readonly attribute int16u subjectsPerAccessControlEntry = 2; + readonly attribute int16u targetsPerAccessControlEntry = 3; + readonly attribute int16u accessControlEntriesPerFabric = 4; + 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; +} + +/** This cluster provides attributes and events for determining basic information about Nodes, which supports both + Commissioning and operational determination of Node characteristics, such as Vendor ID, Product ID and serial number, + which apply to the whole Node. Also allows setting user device information such as location. */ +server cluster BasicInformation = 40 { + enum ColorEnum : ENUM8 { + kBlack = 0; + kNavy = 1; + kGreen = 2; + kTeal = 3; + kMaroon = 4; + kPurple = 5; + kOlive = 6; + kGray = 7; + kBlue = 8; + kLime = 9; + kAqua = 10; + kRed = 11; + kFuchsia = 12; + kYellow = 13; + kWhite = 14; + kNickel = 15; + kChrome = 16; + kBrass = 17; + kCopper = 18; + kSilver = 19; + kGold = 20; + } + + enum ProductFinishEnum : ENUM8 { + kOther = 0; + kMatte = 1; + kSatin = 2; + kPolished = 3; + kRugged = 4; + kFabric = 5; + } + + struct CapabilityMinimaStruct { + int16u caseSessionsPerFabric = 0; + int16u subscriptionsPerFabric = 1; + } + + struct ProductAppearanceStruct { + ProductFinishEnum finish = 0; + nullable ColorEnum primaryColor = 1; + } + + critical event StartUp = 0 { + INT32U softwareVersion = 0; + } + + critical event ShutDown = 1 { + } + + info event Leave = 2 { + fabric_idx fabricIndex = 0; + } + + info event ReachableChanged = 3 { + boolean reachableNewValue = 0; + } + + readonly attribute int16u dataModelRevision = 0; + readonly attribute char_string<32> vendorName = 1; + readonly attribute vendor_id vendorID = 2; + readonly attribute char_string<32> productName = 3; + readonly attribute int16u productID = 4; + attribute access(write: manage) char_string<32> nodeLabel = 5; + attribute access(write: administer) char_string<2> location = 6; + readonly attribute int16u hardwareVersion = 7; + readonly attribute char_string<64> hardwareVersionString = 8; + readonly attribute int32u softwareVersion = 9; + readonly attribute char_string<64> softwareVersionString = 10; + readonly attribute char_string<16> manufacturingDate = 11; + readonly attribute char_string<32> partNumber = 12; + readonly attribute long_char_string<256> productURL = 13; + readonly attribute char_string<64> productLabel = 14; + readonly attribute char_string<32> serialNumber = 15; + attribute access(write: manage) boolean localConfigDisabled = 16; + readonly attribute boolean reachable = 17; + readonly attribute char_string<32> uniqueID = 18; + readonly attribute CapabilityMinimaStruct capabilityMinima = 19; + 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; +} + +/** Provides an interface for providing OTA software updates */ +server cluster OtaSoftwareUpdateProvider = 41 { + enum OTAApplyUpdateAction : ENUM8 { + kProceed = 0; + kAwaitNextAction = 1; + kDiscontinue = 2; + } + + enum OTADownloadProtocol : ENUM8 { + kBDXSynchronous = 0; + kBDXAsynchronous = 1; + kHTTPS = 2; + kVendorSpecific = 3; + } + + enum OTAQueryStatus : ENUM8 { + kUpdateAvailable = 0; + kBusy = 1; + kNotAvailable = 2; + kDownloadProtocolNotSupported = 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 QueryImageRequest { + vendor_id vendorID = 0; + INT16U productID = 1; + INT32U softwareVersion = 2; + OTADownloadProtocol protocolsSupported[] = 3; + optional INT16U hardwareVersion = 4; + optional CHAR_STRING<2> location = 5; + optional BOOLEAN requestorCanConsent = 6; + optional OCTET_STRING<512> metadataForProvider = 7; + } + + request struct ApplyUpdateRequestRequest { + OCTET_STRING<32> updateToken = 0; + INT32U newVersion = 1; + } + + request struct NotifyUpdateAppliedRequest { + OCTET_STRING<32> updateToken = 0; + INT32U softwareVersion = 1; + } + + response struct QueryImageResponse = 1 { + OTAQueryStatus status = 0; + optional INT32U delayedActionTime = 1; + optional CHAR_STRING<256> imageURI = 2; + optional INT32U softwareVersion = 3; + optional CHAR_STRING<64> softwareVersionString = 4; + optional OCTET_STRING<32> updateToken = 5; + optional BOOLEAN userConsentNeeded = 6; + optional OCTET_STRING<512> metadataForRequestor = 7; + } + + response struct ApplyUpdateResponse = 3 { + OTAApplyUpdateAction action = 0; + INT32U delayedActionTime = 1; + } + + command QueryImage(QueryImageRequest): QueryImageResponse = 0; + command ApplyUpdateRequest(ApplyUpdateRequestRequest): ApplyUpdateResponse = 2; + command NotifyUpdateApplied(NotifyUpdateAppliedRequest): DefaultSuccess = 4; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing common languages, units of measurements, and numerical formatting + standards. As such, Nodes that visually or audibly convey information need a mechanism by which + they can be configured to use a user’s preferred language, units, etc */ +server cluster LocalizationConfiguration = 43 { + attribute char_string<35> activeLocale = 0; + readonly attribute CHAR_STRING supportedLocales[] = 1; + 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; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing preferences for how dates and times are conveyed. As such, Nodes that visually + or audibly convey time information need a mechanism by which they can be configured to use a + user’s preferred format. */ +server cluster TimeFormatLocalization = 44 { + enum CalendarTypeEnum : ENUM8 { + kBuddhist = 0; + kChinese = 1; + kCoptic = 2; + kEthiopian = 3; + kGregorian = 4; + kHebrew = 5; + kIndian = 6; + kIslamic = 7; + kJapanese = 8; + kKorean = 9; + kPersian = 10; + kTaiwanese = 11; + } + + enum HourFormatEnum : ENUM8 { + k12hr = 0; + k24hr = 1; + } + + attribute HourFormatEnum hourFormat = 0; + attribute CalendarTypeEnum activeCalendarType = 1; + readonly attribute CalendarTypeEnum supportedCalendarTypes[] = 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; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing preferences for the units in which values are conveyed in communication to a + user. As such, Nodes that visually or audibly convey measurable values to the user need a + mechanism by which they can be configured to use a user’s preferred unit. */ +server cluster UnitLocalization = 45 { + enum TempUnitEnum : ENUM8 { + kFahrenheit = 0; + kCelsius = 1; + kKelvin = 2; + } + + bitmap Feature : BITMAP32 { + kTemperatureUnit = 0x1; + } + + attribute TempUnitEnum temperatureUnit = 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; +} + +/** This cluster is used to manage global aspects of the Commissioning flow. */ +server cluster GeneralCommissioning = 48 { + enum CommissioningErrorEnum : ENUM8 { + kOK = 0; + kValueOutsideRange = 1; + kInvalidAuthentication = 2; + kNoFailSafe = 3; + kBusyWithOtherAdmin = 4; + } + + enum RegulatoryLocationTypeEnum : ENUM8 { + kIndoor = 0; + kOutdoor = 1; + kIndoorOutdoor = 2; + } + + struct BasicCommissioningInfo { + int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; + } + + attribute access(write: administer) int64u breadcrumb = 0; + readonly attribute BasicCommissioningInfo basicCommissioningInfo = 1; + readonly attribute RegulatoryLocationTypeEnum regulatoryConfig = 2; + readonly attribute RegulatoryLocationTypeEnum locationCapability = 3; + readonly attribute boolean supportsConcurrentConnection = 4; + 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 ArmFailSafeRequest { + INT16U expiryLengthSeconds = 0; + INT64U breadcrumb = 1; + } + + request struct SetRegulatoryConfigRequest { + RegulatoryLocationTypeEnum newRegulatoryConfig = 0; + CHAR_STRING countryCode = 1; + INT64U breadcrumb = 2; + } + + response struct ArmFailSafeResponse = 1 { + CommissioningErrorEnum errorCode = 0; + CHAR_STRING debugText = 1; + } + + response struct SetRegulatoryConfigResponse = 3 { + CommissioningErrorEnum errorCode = 0; + CHAR_STRING debugText = 1; + } + + response struct CommissioningCompleteResponse = 5 { + CommissioningErrorEnum errorCode = 0; + CHAR_STRING debugText = 1; + } + + command access(invoke: administer) ArmFailSafe(ArmFailSafeRequest): ArmFailSafeResponse = 0; + command access(invoke: administer) SetRegulatoryConfig(SetRegulatoryConfigRequest): SetRegulatoryConfigResponse = 2; + fabric command access(invoke: administer) CommissioningComplete(): CommissioningCompleteResponse = 4; +} + +/** Functionality to configure, enable, disable network credentials and access on a Matter device. */ +server cluster NetworkCommissioning = 49 { + enum NetworkCommissioningStatusEnum : ENUM8 { + kSuccess = 0; + kOutOfRange = 1; + kBoundsExceeded = 2; + kNetworkIDNotFound = 3; + kDuplicateNetworkID = 4; + kNetworkNotFound = 5; + kRegulatoryError = 6; + kAuthFailure = 7; + kUnsupportedSecurity = 8; + kOtherConnectionFailure = 9; + kIPV6Failed = 10; + kIPBindFailed = 11; + kUnknownError = 12; + } + + enum WiFiBandEnum : ENUM8 { + k2G4 = 0; + k3G65 = 1; + k5G = 2; + k6G = 3; + k60G = 4; + k1G = 5; + } + + bitmap Feature : BITMAP32 { + kWiFiNetworkInterface = 0x1; + kThreadNetworkInterface = 0x2; + kEthernetNetworkInterface = 0x4; + } + + bitmap WiFiSecurityBitmap : BITMAP8 { + kUnencrypted = 0x1; + kWEP = 0x2; + kWPAPersonal = 0x4; + kWPA2Personal = 0x8; + kWPA3Personal = 0x10; + } + + struct NetworkInfoStruct { + octet_string<32> networkID = 0; + boolean connected = 1; + } + + struct ThreadInterfaceScanResultStruct { + int16u panId = 0; + int64u extendedPanId = 1; + char_string<16> networkName = 2; + int16u channel = 3; + int8u version = 4; + octet_string<8> extendedAddress = 5; + int8s rssi = 6; + int8u lqi = 7; + } + + struct WiFiInterfaceScanResultStruct { + WiFiSecurityBitmap security = 0; + octet_string<32> ssid = 1; + octet_string<6> bssid = 2; + int16u channel = 3; + WiFiBandEnum wiFiBand = 4; + int8s rssi = 5; + } + + readonly attribute access(read: administer) int8u maxNetworks = 0; + readonly attribute access(read: administer) NetworkInfoStruct networks[] = 1; + readonly attribute int8u scanMaxTimeSeconds = 2; + readonly attribute int8u connectMaxTimeSeconds = 3; + attribute access(write: administer) boolean interfaceEnabled = 4; + readonly attribute access(read: administer) nullable NetworkCommissioningStatusEnum lastNetworkingStatus = 5; + readonly attribute access(read: administer) nullable octet_string<32> lastNetworkID = 6; + readonly attribute access(read: administer) nullable int32s lastConnectErrorValue = 7; + 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 ScanNetworksRequest { + optional nullable OCTET_STRING<32> ssid = 0; + optional INT64U breadcrumb = 1; + } + + request struct AddOrUpdateWiFiNetworkRequest { + OCTET_STRING<32> ssid = 0; + OCTET_STRING<64> credentials = 1; + optional INT64U breadcrumb = 2; + } + + request struct AddOrUpdateThreadNetworkRequest { + OCTET_STRING<254> operationalDataset = 0; + optional INT64U breadcrumb = 1; + } + + request struct RemoveNetworkRequest { + OCTET_STRING<32> networkID = 0; + optional INT64U breadcrumb = 1; + } + + request struct ConnectNetworkRequest { + OCTET_STRING<32> networkID = 0; + optional INT64U breadcrumb = 1; + } + + request struct ReorderNetworkRequest { + OCTET_STRING<32> networkID = 0; + INT8U networkIndex = 1; + optional INT64U breadcrumb = 2; + } + + response struct ScanNetworksResponse = 1 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional CHAR_STRING debugText = 1; + optional WiFiInterfaceScanResultStruct wiFiScanResults[] = 2; + optional ThreadInterfaceScanResultStruct threadScanResults[] = 3; + } + + response struct NetworkConfigResponse = 5 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional CHAR_STRING<512> debugText = 1; + optional INT8U networkIndex = 2; + } + + response struct ConnectNetworkResponse = 7 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional CHAR_STRING debugText = 1; + nullable INT32S errorValue = 2; + } + + command access(invoke: administer) ScanNetworks(ScanNetworksRequest): ScanNetworksResponse = 0; + command access(invoke: administer) AddOrUpdateWiFiNetwork(AddOrUpdateWiFiNetworkRequest): NetworkConfigResponse = 2; + command access(invoke: administer) AddOrUpdateThreadNetwork(AddOrUpdateThreadNetworkRequest): NetworkConfigResponse = 3; + command access(invoke: administer) RemoveNetwork(RemoveNetworkRequest): NetworkConfigResponse = 4; + command access(invoke: administer) ConnectNetwork(ConnectNetworkRequest): ConnectNetworkResponse = 6; + command access(invoke: administer) ReorderNetwork(ReorderNetworkRequest): NetworkConfigResponse = 8; +} + +/** The cluster provides commands for retrieving unstructured diagnostic logs from a Node that may be used to aid in diagnostics. */ +server cluster DiagnosticLogs = 50 { + enum IntentEnum : ENUM8 { + kEndUserSupport = 0; + kNetworkDiag = 1; + kCrashLogs = 2; + } + + enum StatusEnum : ENUM8 { + kSuccess = 0; + kExhausted = 1; + kNoLogs = 2; + kBusy = 3; + kDenied = 4; + } + + enum TransferProtocolEnum : ENUM8 { + kResponsePayload = 0; + kBDX = 1; + } + + 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 RetrieveLogsRequestRequest { + IntentEnum intent = 0; + TransferProtocolEnum requestedProtocol = 1; + optional CHAR_STRING<32> transferFileDesignator = 2; + } + + command RetrieveLogsRequest(RetrieveLogsRequestRequest): RetrieveLogsResponse = 0; +} + +/** The General Diagnostics Cluster, along with other diagnostics clusters, provide a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +server cluster GeneralDiagnostics = 51 { + enum BootReasonEnum : ENUM8 { + kUnspecified = 0; + kPowerOnReboot = 1; + kBrownOutReset = 2; + kSoftwareWatchdogReset = 3; + kHardwareWatchdogReset = 4; + kSoftwareUpdateCompleted = 5; + kSoftwareReset = 6; + } + + enum HardwareFaultEnum : ENUM8 { + kUnspecified = 0; + kRadio = 1; + kSensor = 2; + kResettableOverTemp = 3; + kNonResettableOverTemp = 4; + kPowerSource = 5; + kVisualDisplayFault = 6; + kAudioOutputFault = 7; + kUserInterfaceFault = 8; + kNonVolatileMemoryError = 9; + kTamperDetected = 10; + } + + enum InterfaceTypeEnum : ENUM8 { + kUnspecified = 0; + kWiFi = 1; + kEthernet = 2; + kCellular = 3; + kThread = 4; + } + + enum NetworkFaultEnum : ENUM8 { + kUnspecified = 0; + kHardwareFailure = 1; + kNetworkJammed = 2; + kConnectionFailed = 3; + } + + enum RadioFaultEnum : ENUM8 { + kUnspecified = 0; + kWiFiFault = 1; + kCellularFault = 2; + kThreadFault = 3; + kNFCFault = 4; + kBLEFault = 5; + kEthernetFault = 6; + } + + struct NetworkInterface { + char_string<32> name = 0; + boolean isOperational = 1; + nullable boolean offPremiseServicesReachableIPv4 = 2; + nullable boolean offPremiseServicesReachableIPv6 = 3; + octet_string<8> hardwareAddress = 4; + octet_string IPv4Addresses[] = 5; + octet_string IPv6Addresses[] = 6; + InterfaceTypeEnum type = 7; + } + + critical event HardwareFaultChange = 0 { + HardwareFaultEnum current[] = 0; + HardwareFaultEnum previous[] = 1; + } + + critical event RadioFaultChange = 1 { + RadioFaultEnum current[] = 0; + RadioFaultEnum previous[] = 1; + } + + critical event NetworkFaultChange = 2 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + critical event BootReason = 3 { + BootReasonEnum bootReason = 0; + } + + readonly attribute NetworkInterface networkInterfaces[] = 0; + readonly attribute int16u rebootCount = 1; + readonly attribute int64u upTime = 2; + readonly attribute int32u totalOperationalHours = 3; + readonly attribute BootReasonEnum bootReason = 4; + readonly attribute HardwareFaultEnum activeHardwareFaults[] = 5; + readonly attribute RadioFaultEnum activeRadioFaults[] = 6; + readonly attribute NetworkFaultEnum activeNetworkFaults[] = 7; + readonly attribute boolean testEventTriggersEnabled = 8; + 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 TestEventTriggerRequest { + OCTET_STRING<16> enableKey = 0; + INT64U eventTrigger = 1; + } + + command access(invoke: manage) TestEventTrigger(TestEventTriggerRequest): DefaultSuccess = 0; +} + +/** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +server cluster SoftwareDiagnostics = 52 { + bitmap Feature : BITMAP32 { + kWaterMarks = 0x1; + } + + struct ThreadMetricsStruct { + int64u id = 0; + optional char_string<8> name = 1; + optional int32u stackFreeCurrent = 2; + optional int32u stackFreeMinimum = 3; + optional int32u stackSize = 4; + } + + info event SoftwareFault = 0 { + INT64U id = 0; + optional CHAR_STRING name = 1; + optional OCTET_STRING faultRecording = 2; + } + + readonly attribute ThreadMetricsStruct threadMetrics[] = 0; + readonly attribute int64u currentHeapFree = 1; + readonly attribute int64u currentHeapUsed = 2; + readonly attribute int64u currentHeapHighWatermark = 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; +} + +/** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ +server cluster ThreadNetworkDiagnostics = 53 { + enum ConnectionStatusEnum : ENUM8 { + kConnected = 0; + kNotConnected = 1; + } + + enum NetworkFaultEnum : ENUM8 { + kUnspecified = 0; + kLinkDown = 1; + kHardwareFailure = 2; + kNetworkJammed = 3; + } + + enum RoutingRoleEnum : ENUM8 { + kUnspecified = 0; + kUnassigned = 1; + kSleepyEndDevice = 2; + kEndDevice = 3; + kREED = 4; + kRouter = 5; + kLeader = 6; + } + + bitmap Feature : BITMAP32 { + kPacketCounts = 0x1; + kErrorCounts = 0x2; + kMLECounts = 0x4; + kMACCounts = 0x8; + } + + struct NeighborTableStruct { + int64u extAddress = 0; + int32u age = 1; + int16u rloc16 = 2; + int32u linkFrameCounter = 3; + int32u mleFrameCounter = 4; + int8u lqi = 5; + nullable int8s averageRssi = 6; + nullable int8s lastRssi = 7; + int8u frameErrorRate = 8; + int8u messageErrorRate = 9; + boolean rxOnWhenIdle = 10; + boolean fullThreadDevice = 11; + boolean fullNetworkData = 12; + boolean isChild = 13; + } + + struct OperationalDatasetComponents { + boolean activeTimestampPresent = 0; + boolean pendingTimestampPresent = 1; + boolean masterKeyPresent = 2; + boolean networkNamePresent = 3; + boolean extendedPanIdPresent = 4; + boolean meshLocalPrefixPresent = 5; + boolean delayPresent = 6; + boolean panIdPresent = 7; + boolean channelPresent = 8; + boolean pskcPresent = 9; + boolean securityPolicyPresent = 10; + boolean channelMaskPresent = 11; + } + + struct RouteTableStruct { + int64u extAddress = 0; + int16u rloc16 = 1; + int8u routerId = 2; + int8u nextHop = 3; + int8u pathCost = 4; + int8u LQIIn = 5; + int8u LQIOut = 6; + int8u age = 7; + boolean allocated = 8; + boolean linkEstablished = 9; + } + + struct SecurityPolicy { + int16u rotationTime = 0; + int16u flags = 1; + } + + info event ConnectionStatus = 0 { + ConnectionStatusEnum connectionStatus = 0; + } + + info event NetworkFaultChange = 1 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + readonly attribute nullable int16u channel = 0; + readonly attribute nullable RoutingRoleEnum routingRole = 1; + readonly attribute nullable char_string<16> networkName = 2; + readonly attribute nullable int16u panId = 3; + readonly attribute nullable int64u extendedPanId = 4; + readonly attribute nullable octet_string<17> meshLocalPrefix = 5; + readonly attribute int64u overrunCount = 6; + readonly attribute NeighborTableStruct neighborTable[] = 7; + readonly attribute RouteTableStruct routeTable[] = 8; + readonly attribute nullable int32u partitionId = 9; + readonly attribute nullable int8u weighting = 10; + readonly attribute nullable int8u dataVersion = 11; + readonly attribute nullable int8u stableDataVersion = 12; + readonly attribute nullable int8u leaderRouterId = 13; + readonly attribute int16u detachedRoleCount = 14; + readonly attribute int16u childRoleCount = 15; + readonly attribute int16u routerRoleCount = 16; + readonly attribute int16u leaderRoleCount = 17; + readonly attribute int16u attachAttemptCount = 18; + readonly attribute int16u partitionIdChangeCount = 19; + readonly attribute int16u betterPartitionAttachAttemptCount = 20; + readonly attribute int16u parentChangeCount = 21; + readonly attribute int32u txTotalCount = 22; + readonly attribute int32u txUnicastCount = 23; + readonly attribute int32u txBroadcastCount = 24; + readonly attribute int32u txAckRequestedCount = 25; + readonly attribute int32u txAckedCount = 26; + readonly attribute int32u txNoAckRequestedCount = 27; + readonly attribute int32u txDataCount = 28; + readonly attribute int32u txDataPollCount = 29; + readonly attribute int32u txBeaconCount = 30; + readonly attribute int32u txBeaconRequestCount = 31; + readonly attribute int32u txOtherCount = 32; + readonly attribute int32u txRetryCount = 33; + readonly attribute int32u txDirectMaxRetryExpiryCount = 34; + readonly attribute int32u txIndirectMaxRetryExpiryCount = 35; + readonly attribute int32u txErrCcaCount = 36; + readonly attribute int32u txErrAbortCount = 37; + readonly attribute int32u txErrBusyChannelCount = 38; + readonly attribute int32u rxTotalCount = 39; + readonly attribute int32u rxUnicastCount = 40; + readonly attribute int32u rxBroadcastCount = 41; + readonly attribute int32u rxDataCount = 42; + readonly attribute int32u rxDataPollCount = 43; + readonly attribute int32u rxBeaconCount = 44; + readonly attribute int32u rxBeaconRequestCount = 45; + readonly attribute int32u rxOtherCount = 46; + readonly attribute int32u rxAddressFilteredCount = 47; + readonly attribute int32u rxDestAddrFilteredCount = 48; + readonly attribute int32u rxDuplicatedCount = 49; + readonly attribute int32u rxErrNoFrameCount = 50; + readonly attribute int32u rxErrUnknownNeighborCount = 51; + readonly attribute int32u rxErrInvalidSrcAddrCount = 52; + readonly attribute int32u rxErrSecCount = 53; + readonly attribute int32u rxErrFcsCount = 54; + readonly attribute int32u rxErrOtherCount = 55; + readonly attribute nullable int64u activeTimestamp = 56; + readonly attribute nullable int64u pendingTimestamp = 57; + readonly attribute nullable int32u delay = 58; + readonly attribute nullable SecurityPolicy securityPolicy = 59; + readonly attribute nullable octet_string<4> channelPage0Mask = 60; + readonly attribute nullable OperationalDatasetComponents operationalDatasetComponents = 61; + readonly attribute NetworkFaultEnum activeNetworkFaultsList[] = 62; + 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; +} + +/** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +server cluster WiFiNetworkDiagnostics = 54 { + enum AssociationFailureCauseEnum : ENUM8 { + kUnknown = 0; + kAssociationFailed = 1; + kAuthenticationFailed = 2; + kSsidNotFound = 3; + } + + enum ConnectionStatusEnum : ENUM8 { + kConnected = 0; + kNotConnected = 1; + } + + enum SecurityTypeEnum : ENUM8 { + kUnspecified = 0; + kNone = 1; + kWEP = 2; + kWPA = 3; + kWPA2 = 4; + kWPA3 = 5; + } + + enum WiFiVersionEnum : ENUM8 { + kA = 0; + kB = 1; + kG = 2; + kN = 3; + kAc = 4; + kAx = 5; + kAh = 6; + } + + bitmap Feature : BITMAP32 { + kPacketCounts = 0x1; + kErrorCounts = 0x2; + } + + info event Disconnection = 0 { + INT16U reasonCode = 0; + } + + info event AssociationFailure = 1 { + AssociationFailureCauseEnum associationFailure = 0; + INT16U status = 1; + } + + info event ConnectionStatus = 2 { + ConnectionStatusEnum connectionStatus = 0; + } + + readonly attribute nullable octet_string<6> bssid = 0; + readonly attribute nullable SecurityTypeEnum securityType = 1; + readonly attribute nullable WiFiVersionEnum wiFiVersion = 2; + readonly attribute nullable int16u channelNumber = 3; + readonly attribute nullable int8s rssi = 4; + readonly attribute nullable int32u beaconLostCount = 5; + readonly attribute nullable int32u beaconRxCount = 6; + readonly attribute nullable int32u packetMulticastRxCount = 7; + readonly attribute nullable int32u packetMulticastTxCount = 8; + readonly attribute nullable int32u packetUnicastRxCount = 9; + readonly attribute nullable int32u packetUnicastTxCount = 10; + readonly attribute nullable int64u currentMaxRate = 11; + readonly attribute nullable int64u overrunCount = 12; + 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; +} + +/** The Ethernet Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +server cluster EthernetNetworkDiagnostics = 55 { + enum PHYRateEnum : ENUM8 { + kRate10M = 0; + kRate100M = 1; + kRate1G = 2; + kRate25G = 3; + kRate5G = 4; + kRate10G = 5; + kRate40G = 6; + kRate100G = 7; + kRate200G = 8; + kRate400G = 9; + } + + bitmap Feature : BITMAP32 { + kPacketCounts = 0x1; + kErrorCounts = 0x2; + } + + readonly attribute nullable PHYRateEnum PHYRate = 0; + readonly attribute nullable boolean fullDuplex = 1; + readonly attribute int64u packetRxCount = 2; + readonly attribute int64u packetTxCount = 3; + readonly attribute int64u txErrCount = 4; + readonly attribute int64u collisionCount = 5; + readonly attribute int64u overrunCount = 6; + readonly attribute nullable boolean carrierDetect = 7; + readonly attribute int64u timeSinceReset = 8; + 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; + + command ResetCounts(): DefaultSuccess = 0; +} + +/** Commands to trigger a Node to allow a new Administrator to commission it. */ +server cluster AdministratorCommissioning = 60 { + enum CommissioningWindowStatusEnum : ENUM8 { + kWindowNotOpen = 0; + kEnhancedWindowOpen = 1; + kBasicWindowOpen = 2; + } + + enum StatusCode : ENUM8 { + kBusy = 2; + kPAKEParameterError = 3; + kWindowNotOpen = 4; + } + + readonly attribute CommissioningWindowStatusEnum windowStatus = 0; + readonly attribute nullable fabric_idx adminFabricIndex = 1; + readonly attribute nullable int16u adminVendorId = 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; + + request struct OpenCommissioningWindowRequest { + INT16U commissioningTimeout = 0; + OCTET_STRING PAKEPasscodeVerifier = 1; + INT16U discriminator = 2; + INT32U iterations = 3; + OCTET_STRING salt = 4; + } + + request struct OpenBasicCommissioningWindowRequest { + INT16U commissioningTimeout = 0; + } + + timed command access(invoke: administer) OpenCommissioningWindow(OpenCommissioningWindowRequest): DefaultSuccess = 0; + timed command access(invoke: administer) OpenBasicCommissioningWindow(OpenBasicCommissioningWindowRequest): DefaultSuccess = 1; + timed command access(invoke: administer) RevokeCommissioning(): DefaultSuccess = 2; +} + +/** This cluster is used to add or remove Operational Credentials on a Commissionee or Node, as well as manage the associated Fabrics. */ +server cluster OperationalCredentials = 62 { + enum CertificateChainTypeEnum : ENUM8 { + kDACCertificate = 1; + kPAICertificate = 2; + } + + enum NodeOperationalCertStatusEnum : ENUM8 { + kOK = 0; + kInvalidPublicKey = 1; + kInvalidNodeOpId = 2; + kInvalidNOC = 3; + kMissingCsr = 4; + kTableFull = 5; + kInvalidAdminSubject = 6; + kFabricConflict = 9; + kLabelConflict = 10; + kInvalidFabricIndex = 11; + } + + fabric_scoped struct FabricDescriptorStruct { + octet_string<65> rootPublicKey = 1; + vendor_id vendorID = 2; + fabric_id fabricID = 3; + node_id nodeID = 4; + char_string<32> label = 5; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct NOCStruct { + fabric_sensitive octet_string noc = 1; + nullable fabric_sensitive octet_string icac = 2; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: administer) NOCStruct NOCs[] = 0; + readonly attribute FabricDescriptorStruct fabrics[] = 1; + readonly attribute int8u supportedFabrics = 2; + readonly attribute int8u commissionedFabrics = 3; + readonly attribute OCTET_STRING trustedRootCertificates[] = 4; + readonly attribute int8u currentFabricIndex = 5; + 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 AttestationRequestRequest { + OCTET_STRING attestationNonce = 0; + } + + request struct CertificateChainRequestRequest { + CertificateChainTypeEnum certificateType = 0; + } + + request struct CSRRequestRequest { + OCTET_STRING CSRNonce = 0; + optional boolean isForUpdateNOC = 1; + } + + request struct AddNOCRequest { + OCTET_STRING NOCValue = 0; + optional OCTET_STRING ICACValue = 1; + OCTET_STRING IPKValue = 2; + Int64u caseAdminSubject = 3; + VENDOR_ID adminVendorId = 4; + } + + request struct UpdateNOCRequest { + OCTET_STRING NOCValue = 0; + optional OCTET_STRING ICACValue = 1; + } + + request struct UpdateFabricLabelRequest { + CHAR_STRING<32> label = 0; + } + + request struct RemoveFabricRequest { + fabric_idx fabricIndex = 0; + } + + request struct AddTrustedRootCertificateRequest { + OCTET_STRING rootCACertificate = 0; + } + + response struct AttestationResponse = 1 { + OCTET_STRING attestationElements = 0; + OCTET_STRING attestationSignature = 1; + } + + response struct CertificateChainResponse = 3 { + OCTET_STRING certificate = 0; + } + + response struct CSRResponse = 5 { + OCTET_STRING NOCSRElements = 0; + OCTET_STRING attestationSignature = 1; + } + + response struct NOCResponse = 8 { + NodeOperationalCertStatusEnum statusCode = 0; + optional fabric_idx fabricIndex = 1; + optional CHAR_STRING debugText = 2; + } + + command access(invoke: administer) AttestationRequest(AttestationRequestRequest): AttestationResponse = 0; + command access(invoke: administer) CertificateChainRequest(CertificateChainRequestRequest): CertificateChainResponse = 2; + command access(invoke: administer) CSRRequest(CSRRequestRequest): CSRResponse = 4; + command access(invoke: administer) AddNOC(AddNOCRequest): NOCResponse = 6; + fabric command access(invoke: administer) UpdateNOC(UpdateNOCRequest): NOCResponse = 7; + fabric command access(invoke: administer) UpdateFabricLabel(UpdateFabricLabelRequest): NOCResponse = 9; + command access(invoke: administer) RemoveFabric(RemoveFabricRequest): NOCResponse = 10; + command access(invoke: administer) AddTrustedRootCertificate(AddTrustedRootCertificateRequest): DefaultSuccess = 11; +} + +/** The Group Key Management Cluster is the mechanism by which group keys are managed. */ +server cluster GroupKeyManagement = 63 { + enum GroupKeySecurityPolicyEnum : ENUM8 { + kTrustFirst = 0; + kCacheAndSync = 1; + } + + fabric_scoped struct GroupInfoMapStruct { + group_id groupId = 1; + endpoint_no endpoints[] = 2; + optional char_string<16> groupName = 3; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct GroupKeyMapStruct { + group_id groupId = 1; + int16u groupKeySetID = 2; + fabric_idx fabricIndex = 254; + } + + struct GroupKeySetStruct { + int16u groupKeySetID = 0; + GroupKeySecurityPolicyEnum groupKeySecurityPolicy = 1; + nullable octet_string<16> epochKey0 = 2; + nullable epoch_us epochStartTime0 = 3; + nullable octet_string<16> epochKey1 = 4; + nullable epoch_us epochStartTime1 = 5; + nullable octet_string<16> epochKey2 = 6; + nullable epoch_us epochStartTime2 = 7; + } + + attribute access(write: manage) GroupKeyMapStruct groupKeyMap[] = 0; + readonly attribute GroupInfoMapStruct groupTable[] = 1; + readonly attribute int16u maxGroupsPerFabric = 2; + readonly attribute int16u maxGroupKeysPerFabric = 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 KeySetWriteRequest { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetReadRequest { + INT16U groupKeySetID = 0; + } + + request struct KeySetRemoveRequest { + INT16U groupKeySetID = 0; + } + + response struct KeySetReadResponse = 2 { + GroupKeySetStruct groupKeySet = 0; + } + + response struct KeySetReadAllIndicesResponse = 5 { + INT16U groupKeySetIDs[] = 0; + } + + fabric command access(invoke: administer) KeySetWrite(KeySetWriteRequest): DefaultSuccess = 0; + fabric command access(invoke: administer) KeySetRead(KeySetReadRequest): KeySetReadResponse = 1; + fabric command access(invoke: administer) KeySetRemove(KeySetRemoveRequest): DefaultSuccess = 3; + fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; +} + +/** The Fixed Label Cluster provides a feature for the device to tag an endpoint with zero or more read only +labels. */ +server cluster FixedLabel = 64 { + struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; + } + + readonly attribute LabelStruct labelList[] = 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; +} + +/** The User Label Cluster provides a feature to tag an endpoint with zero or more labels. */ +server cluster UserLabel = 65 { + struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; + } + + attribute access(write: manage) LabelStruct labelList[] = 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; +} + +endpoint 0 { + device type rootdevice = 22, version 1; + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + ram attribute featureMap default = 0; + callback attribute clusterRevision default = 1; + } + + server cluster Binding { + callback attribute binding; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster AccessControl { + emits event AccessControlEntryChanged; + emits event AccessControlExtensionChanged; + callback attribute acl; + callback attribute extension; + callback attribute subjectsPerAccessControlEntry default = 4; + callback attribute targetsPerAccessControlEntry default = 3; + callback attribute accessControlEntriesPerFabric default = 4; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster BasicInformation { + emits event StartUp; + emits event ShutDown; + emits event Leave; + callback attribute dataModelRevision default = 10; + callback attribute vendorName; + callback attribute vendorID; + callback attribute productName; + callback attribute productID; + persist attribute nodeLabel; + callback attribute location default = "XX"; + callback attribute hardwareVersion default = 0; + callback attribute hardwareVersionString; + callback attribute softwareVersion default = 0; + callback attribute softwareVersionString; + callback attribute manufacturingDate default = "20210614123456ZZ"; + callback attribute partNumber; + callback attribute productURL; + callback attribute productLabel; + callback attribute serialNumber; + persist attribute localConfigDisabled default = 0; + ram attribute reachable default = 1; + callback attribute uniqueID; + callback attribute capabilityMinima; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster OtaSoftwareUpdateProvider { + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster LocalizationConfiguration { + persist attribute activeLocale default = "en-US"; + callback attribute supportedLocales; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster TimeFormatLocalization { + persist attribute hourFormat default = 0; + persist attribute activeCalendarType default = 0; + callback attribute supportedCalendarTypes; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster UnitLocalization { + persist attribute temperatureUnit default = 0; + ram attribute featureMap default = 0x1; + ram attribute clusterRevision default = 1; + } + + server cluster GeneralCommissioning { + ram attribute breadcrumb default = 0x0000000000000000; + callback attribute basicCommissioningInfo; + callback attribute regulatoryConfig default = 0; + callback attribute locationCapability default = 0; + callback attribute supportsConcurrentConnection default = 1; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster NetworkCommissioning { + ram attribute maxNetworks; + callback attribute networks; + ram attribute scanMaxTimeSeconds; + ram attribute connectMaxTimeSeconds; + ram attribute interfaceEnabled; + ram attribute lastNetworkingStatus; + ram attribute lastNetworkID; + ram attribute lastConnectErrorValue; + ram attribute featureMap default = 4; + ram attribute clusterRevision default = 1; + } + + server cluster DiagnosticLogs { + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster GeneralDiagnostics { + emits event BootReason; + callback attribute networkInterfaces; + callback attribute rebootCount default = 0x0000; + callback attribute upTime default = 0x0000000000000000; + callback attribute totalOperationalHours default = 0x00000000; + callback attribute bootReason; + callback attribute activeHardwareFaults; + callback attribute activeRadioFaults; + callback attribute activeNetworkFaults; + callback attribute testEventTriggersEnabled default = false; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster SoftwareDiagnostics { + emits event SoftwareFault; + callback attribute threadMetrics; + callback attribute currentHeapFree default = 0x0000000000000000; + callback attribute currentHeapUsed default = 0x0000000000000000; + callback attribute currentHeapHighWatermark default = 0x0000000000000000; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 1; + } + + server cluster ThreadNetworkDiagnostics { + emits event ConnectionStatus; + emits event NetworkFaultChange; + callback attribute channel; + callback attribute routingRole; + callback attribute networkName default = "0"; + callback attribute panId default = 0x0000; + callback attribute extendedPanId default = 0x0000000000000000; + callback attribute meshLocalPrefix; + callback attribute overrunCount default = 0x0000000000000000; + callback attribute neighborTable; + callback attribute routeTable; + callback attribute partitionId; + callback attribute weighting; + callback attribute dataVersion; + callback attribute stableDataVersion; + callback attribute leaderRouterId; + callback attribute detachedRoleCount default = 0x0000; + callback attribute childRoleCount default = 0x0000; + callback attribute routerRoleCount default = 0x0000; + callback attribute leaderRoleCount default = 0x0000; + callback attribute attachAttemptCount default = 0x0000; + callback attribute partitionIdChangeCount default = 0x0000; + callback attribute betterPartitionAttachAttemptCount default = 0x0000; + callback attribute parentChangeCount default = 0x0000; + callback attribute txTotalCount default = 0x0000; + callback attribute txUnicastCount default = 0x0000; + callback attribute txBroadcastCount default = 0x0000; + callback attribute txAckRequestedCount default = 0x0000; + callback attribute txAckedCount default = 0x0000; + callback attribute txNoAckRequestedCount default = 0x0000; + callback attribute txDataCount default = 0x0000; + callback attribute txDataPollCount default = 0x0000; + callback attribute txBeaconCount default = 0x0000; + callback attribute txBeaconRequestCount default = 0x0000; + callback attribute txOtherCount default = 0x0000; + callback attribute txRetryCount default = 0x0000; + callback attribute txDirectMaxRetryExpiryCount default = 0x0000; + callback attribute txIndirectMaxRetryExpiryCount default = 0x0000; + callback attribute txErrCcaCount default = 0x0000; + callback attribute txErrAbortCount default = 0x0000; + callback attribute txErrBusyChannelCount default = 0x0000; + callback attribute rxTotalCount default = 0x0000; + callback attribute rxUnicastCount default = 0x0000; + callback attribute rxBroadcastCount default = 0x0000; + callback attribute rxDataCount default = 0x0000; + callback attribute rxDataPollCount default = 0x0000; + callback attribute rxBeaconCount default = 0x0000; + callback attribute rxBeaconRequestCount default = 0x0000; + callback attribute rxOtherCount default = 0x0000; + callback attribute rxAddressFilteredCount default = 0x0000; + callback attribute rxDestAddrFilteredCount default = 0x0000; + callback attribute rxDuplicatedCount default = 0x0000; + callback attribute rxErrNoFrameCount default = 0x0000; + callback attribute rxErrUnknownNeighborCount default = 0x0000; + callback attribute rxErrInvalidSrcAddrCount default = 0x0000; + callback attribute rxErrSecCount default = 0x0000; + callback attribute rxErrFcsCount default = 0x0000; + callback attribute rxErrOtherCount default = 0x0000; + callback attribute activeTimestamp default = 0x0000000000000000; + callback attribute pendingTimestamp default = 0x0000000000000000; + callback attribute delay default = 0x0000; + callback attribute securityPolicy; + callback attribute channelPage0Mask default = "0x0000"; + callback attribute operationalDatasetComponents; + callback attribute activeNetworkFaultsList; + ram attribute featureMap default = 0x000F; + ram attribute clusterRevision default = 1; + } + + server cluster WiFiNetworkDiagnostics { + emits event Disconnection; + emits event AssociationFailure; + emits event ConnectionStatus; + callback attribute bssid; + callback attribute securityType; + callback attribute wiFiVersion; + callback attribute channelNumber default = 0x0000; + callback attribute rssi default = 0x00; + callback attribute beaconLostCount default = 0x00000000; + callback attribute beaconRxCount default = 0x00000000; + callback attribute packetMulticastRxCount default = 0x00000000; + callback attribute packetMulticastTxCount default = 0x00000000; + callback attribute packetUnicastRxCount default = 0x00000000; + callback attribute packetUnicastTxCount default = 0x00000000; + callback attribute currentMaxRate default = 0x0000000000000000; + callback attribute overrunCount default = 0x0000000000000000; + ram attribute featureMap default = 3; + ram attribute clusterRevision default = 1; + } + + server cluster EthernetNetworkDiagnostics { + callback attribute PHYRate; + callback attribute fullDuplex default = 0x00; + callback attribute packetRxCount default = 0x0000000000000000; + callback attribute packetTxCount default = 0x0000000000000000; + callback attribute txErrCount default = 0x0000000000000000; + callback attribute collisionCount default = 0x0000000000000000; + callback attribute overrunCount default = 0x0000000000000000; + callback attribute carrierDetect default = 0x00; + callback attribute timeSinceReset default = 0x0000000000000000; + ram attribute featureMap default = 3; + ram attribute clusterRevision default = 1; + } + + server cluster AdministratorCommissioning { + callback attribute windowStatus default = 0; + callback attribute adminFabricIndex default = 1; + callback attribute adminVendorId default = 0; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster OperationalCredentials { + callback attribute NOCs; + callback attribute fabrics; + callback attribute supportedFabrics; + callback attribute commissionedFabrics; + callback attribute trustedRootCertificates; + callback attribute currentFabricIndex; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster GroupKeyManagement { + callback attribute groupKeyMap; + callback attribute groupTable; + callback attribute maxGroupsPerFabric; + callback attribute maxGroupKeysPerFabric; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster FixedLabel { + callback attribute labelList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster UserLabel { + callback attribute labelList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } +} +endpoint 1 { + device type videoplayer = 256, version 1; + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x0; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 2; + } + + server cluster Groups { + ram attribute nameSupport; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + + server cluster Scenes { + callback attribute sceneCount default = 0x00; + ram attribute currentScene default = 0x00; + ram attribute currentGroup default = 0x0000; + ram attribute sceneValid default = 0x00; + ram attribute nameSupport; + ram attribute sceneTableSize; + callback attribute remainingCapacity; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + + server cluster OnOff { + ram attribute onOff default = 0x00; + ram attribute globalSceneControl default = 1; + ram attribute onTime default = 0; + ram attribute offWaitTime default = 0; + ram attribute startUpOnOff; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 5; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + ram attribute featureMap default = 0; + callback attribute clusterRevision default = 1; + } +} + + diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.zap b/examples/virtual-device-app/virtual-device-common/virtual-device-app.zap new file mode 100644 index 00000000000000..939b94dae34954 --- /dev/null +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.zap @@ -0,0 +1,15641 @@ +{ + "featureLevel": 96, + "creator": "zap", + "keyValuePairs": [ + { + "key": "commandDiscovery", + "value": "1" + }, + { + "key": "defaultResponsePolicy", + "value": "always" + }, + { + "key": "manufacturerCodes", + "value": "0x1002" + } + ], + "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/zcl/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "version": "chip-v1" + } + ], + "endpointTypes": [ + { + "name": "MA-rootdevice", + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Groups", + "code": 4, + "mfgCode": null, + "define": "GROUPS_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "AddGroup", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ViewGroup", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetGroupMembership", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveGroup", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveAllGroups", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "AddGroupIfIdentifying", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Groups", + "code": 4, + "mfgCode": null, + "define": "GROUPS_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "AddGroupResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ViewGroupResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetGroupMembershipResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveGroupResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "NameSupport", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "NameSupportBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Scenes", + "code": 5, + "mfgCode": null, + "define": "SCENES_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "AddScene", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ViewScene", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveScene", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveAllScenes", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StoreScene", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RecallScene", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetSceneMembership", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Scenes", + "code": 5, + "mfgCode": null, + "define": "SCENES_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "AddSceneResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ViewSceneResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveSceneResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveAllScenesResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StoreSceneResponse", + "code": 4, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetSceneMembershipResponse", + "code": 6, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "SceneCount", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentScene", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentGroup", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "group_id", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SceneValid", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NameSupport", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "Off", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "On", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "Toggle", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "OnOff", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "MoveToLevel", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "Move", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "Step", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "Stop", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveToLevelWithOnOff", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveWithOnOff", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StepWithOnOff", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StopWithOnOff", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "CurrentLevel", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "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": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Binding", + "code": 30, + "mfgCode": null, + "define": "BINDING_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Binding", + "code": 30, + "mfgCode": null, + "define": "BINDING_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Binding", + "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": "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ACL", + "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": "Extension", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SubjectsPerAccessControlEntry", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetsPerAccessControlEntry", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AccessControlEntriesPerFabric", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "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": "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": "AccessControlEntryChanged", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "AccessControlExtensionChanged", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DataModelRevision", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "XX", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ManufacturingDate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "20210614123456ZZ", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartNumber", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductURL", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "long_char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductLabel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SerialNumber", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LocalConfigDisabled", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "NVM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Reachable", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UniqueID", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "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": "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": 1, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "StartUp", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "ShutDown", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Leave", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "OTA Software Update Provider", + "code": 41, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "QueryImage", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ApplyUpdateRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "NotifyUpdateApplied", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "OTA Software Update Provider", + "code": 41, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "QueryImageResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "ApplyUpdateResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Localization Configuration", + "code": 43, + "mfgCode": null, + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "Localization Configuration", + "code": 43, + "mfgCode": null, + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ActiveLocale", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "en-US", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedLocales", + "code": 1, + "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": "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 + } + ] + }, + { + "name": "Time Format Localization", + "code": 44, + "mfgCode": null, + "define": "TIME_FORMAT_LOCALIZATION_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "Time Format Localization", + "code": 44, + "mfgCode": null, + "define": "TIME_FORMAT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "HourFormat", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "HourFormatEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveCalendarType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "CalendarTypeEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedCalendarTypes", + "code": 2, + "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": "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 + } + ] + }, + { + "name": "Unit Localization", + "code": 45, + "mfgCode": null, + "define": "UNIT_LOCALIZATION_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "Unit Localization", + "code": 45, + "mfgCode": null, + "define": "UNIT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "TemperatureUnit", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "TempUnitEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "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": "0x1", + "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": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocationCapability", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportsConcurrentConnection", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "ScanNetworks", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "AddOrUpdateWiFiNetwork", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "AddOrUpdateThreadNetwork", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveNetwork", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ConnectNetwork", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ReorderNetwork", + "code": 8, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ScanNetworksResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "NetworkConfigResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ConnectNetworkResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ScanMaxTimeSeconds", + "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": "ConnectMaxTimeSeconds", + "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": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Diagnostic Logs", + "code": 50, + "mfgCode": null, + "define": "DIAGNOSTIC_LOGS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "RetrieveLogsRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "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 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TotalOperationalHours", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BootReason", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "BootReasonEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveHardwareFaults", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveRadioFaults", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveNetworkFaults", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "false", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "BootReason", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Software Diagnostics", + "code": 52, + "mfgCode": null, + "define": "SOFTWARE_DIAGNOSTICS_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "ResetWatermarks", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Software Diagnostics", + "code": 52, + "mfgCode": null, + "define": "SOFTWARE_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ThreadMetrics", + "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": "CurrentHeapFree", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentHeapUsed", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentHeapHighWatermark", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "SoftwareFault", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Thread Network Diagnostics", + "code": 53, + "mfgCode": null, + "define": "THREAD_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Channel", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RoutingRole", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "RoutingRoleEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NetworkName", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PanId", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ExtendedPanId", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MeshLocalPrefix", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "OverrunCount", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NeighborTable", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RouteTable", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartitionId", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Weighting", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "DataVersion", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "StableDataVersion", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LeaderRouterId", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "DetachedRoleCount", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ChildRoleCount", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RouterRoleCount", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LeaderRoleCount", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AttachAttemptCount", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartitionIdChangeCount", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BetterPartitionAttachAttemptCount", + "code": 20, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ParentChangeCount", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxTotalCount", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxUnicastCount", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxBroadcastCount", + "code": 24, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxAckRequestedCount", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxAckedCount", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxNoAckRequestedCount", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxDataCount", + "code": 28, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxDataPollCount", + "code": 29, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxBeaconCount", + "code": 30, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxBeaconRequestCount", + "code": 31, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxOtherCount", + "code": 32, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxRetryCount", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxDirectMaxRetryExpiryCount", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxIndirectMaxRetryExpiryCount", + "code": 35, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxErrCcaCount", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxErrAbortCount", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxErrBusyChannelCount", + "code": 38, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxTotalCount", + "code": 39, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxUnicastCount", + "code": 40, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxBroadcastCount", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxDataCount", + "code": 42, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxDataPollCount", + "code": 43, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxBeaconCount", + "code": 44, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxBeaconRequestCount", + "code": 45, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxOtherCount", + "code": 46, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxAddressFilteredCount", + "code": 47, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxDestAddrFilteredCount", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxDuplicatedCount", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxErrNoFrameCount", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxErrUnknownNeighborCount", + "code": 51, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxErrInvalidSrcAddrCount", + "code": 52, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxErrSecCount", + "code": 53, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxErrFcsCount", + "code": 54, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RxErrOtherCount", + "code": 55, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ActiveTimestamp", + "code": 56, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PendingTimestamp", + "code": 57, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Delay", + "code": 58, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SecurityPolicy", + "code": 59, + "mfgCode": null, + "side": "server", + "type": "SecurityPolicy", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ChannelPage0Mask", + "code": 60, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "OperationalDatasetComponents", + "code": 61, + "mfgCode": null, + "side": "server", + "type": "OperationalDatasetComponents", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ActiveNetworkFaultsList", + "code": 62, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x000F", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "ConnectionStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "NetworkFaultChange", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "WiFi Network Diagnostics", + "code": 54, + "mfgCode": null, + "define": "WIFI_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "WiFi Network Diagnostics", + "code": 54, + "mfgCode": null, + "define": "WIFI_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "BSSID", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SecurityType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "SecurityTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "WiFiVersion", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "WiFiVersionEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ChannelNumber", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RSSI", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int8s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BeaconLostCount", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BeaconRxCount", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketMulticastRxCount", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketMulticastTxCount", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketUnicastRxCount", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketUnicastTxCount", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentMaxRate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OverrunCount", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "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": "3", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "Disconnection", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "AssociationFailure", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "ConnectionStatus", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Ethernet Network Diagnostics", + "code": 55, + "mfgCode": null, + "define": "ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "ResetCounts", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Ethernet Network Diagnostics", + "code": 55, + "mfgCode": null, + "define": "ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "PHYRate", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PHYRateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FullDuplex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PacketRxCount", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PacketTxCount", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TxErrCount", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CollisionCount", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "OverrunCount", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CarrierDetect", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TimeSinceReset", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "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": "3", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Switch", + "code": 59, + "mfgCode": null, + "define": "SWITCH_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Switch", + "code": 59, + "mfgCode": null, + "define": "SWITCH_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "NumberOfPositions", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentPosition", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MultiPressMax", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "OpenBasicCommissioningWindow", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminFabricIndex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "fabric_idx", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "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": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "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": "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "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": "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Fixed Label", + "code": 64, + "mfgCode": null, + "define": "FIXED_LABEL_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "Fixed Label", + "code": 64, + "mfgCode": null, + "define": "FIXED_LABEL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "LabelList", + "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": "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 + } + ] + }, + { + "name": "User Label", + "code": 65, + "mfgCode": null, + "define": "USER_LABEL_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "User Label", + "code": 65, + "mfgCode": null, + "define": "USER_LABEL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "LabelList", + "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": "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 + } + ] + }, + { + "name": "Door Lock", + "code": 257, + "mfgCode": null, + "define": "DOOR_LOCK_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "LockDoor", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "UnlockDoor", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "UnlockWithTimeout", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "SetWeekDaySchedule", + "code": 11, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetWeekDaySchedule", + "code": 12, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ClearWeekDaySchedule", + "code": 13, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "SetYearDaySchedule", + "code": 14, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetYearDaySchedule", + "code": 15, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ClearYearDaySchedule", + "code": 16, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "SetHolidaySchedule", + "code": 17, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetHolidaySchedule", + "code": 18, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ClearHolidaySchedule", + "code": 19, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Door Lock", + "code": 257, + "mfgCode": null, + "define": "DOOR_LOCK_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "LockState", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "DlLockState", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LockType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "DlLockType", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ActuatorEnabled", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "DoorState", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "DoorStateEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Language", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LEDSettings", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AutoRelockTime", + "code": 35, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoundVolume", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "OperatingMode", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "OperatingModeEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "DefaultConfigurationRegister", + "code": 39, + "mfgCode": null, + "side": "server", + "type": "DlDefaultConfigurationRegister", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EnableLocalProgramming", + "code": 40, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EnableOneTouchLocking", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EnableInsideStatusLED", + "code": 42, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EnablePrivacyModeButton", + "code": 43, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "WrongCodeEntryLimit", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UserCodeTemporaryDisableTime", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SendPINOverTheAir", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RequirePINforRemoteOperation", + "code": 51, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Barrier Control", + "code": 259, + "mfgCode": null, + "define": "BARRIER_CONTROL_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "BarrierControlGoToPercent", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "BarrierControlStop", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Barrier Control", + "code": 259, + "mfgCode": null, + "define": "BARRIER_CONTROL_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "barrier moving state", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "barrier safety status", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "bitmap16", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "barrier capabilities", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "barrier position", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Color Control", + "code": 768, + "mfgCode": null, + "define": "COLOR_CONTROL_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "MoveToHue", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveHue", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StepHue", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveToSaturation", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveSaturation", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StepSaturation", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveToHueAndSaturation", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveToColor", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveColor", + "code": 8, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StepColor", + "code": 9, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveToColorTemperature", + "code": 10, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StopMoveStep", + "code": 71, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "MoveColorTemperature", + "code": 75, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StepColorTemperature", + "code": 76, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Color Control", + "code": 768, + "mfgCode": null, + "define": "COLOR_CONTROL_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "CurrentHue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentSaturation", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RemainingTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentX", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x616B", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentY", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x607D", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "DriftCompensation", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CompensationText", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorTemperatureMireds", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00FA", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorMode", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Options", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NumberOfPrimaries", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary1X", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary1Y", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary1Intensity", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary2X", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary2Y", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary2Intensity", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary3X", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary3Y", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary3Intensity", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary4X", + "code": 32, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary4Y", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary4Intensity", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary5X", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary5Y", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary5Intensity", + "code": 38, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary6X", + "code": 40, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary6Y", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Primary6Intensity", + "code": 42, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "WhitePointX", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "WhitePointY", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointRX", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointRY", + "code": 51, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointRIntensity", + "code": 52, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointGX", + "code": 54, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointGY", + "code": 55, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointGIntensity", + "code": 56, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointBX", + "code": 58, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointBY", + "code": 59, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorPointBIntensity", + "code": 60, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EnhancedCurrentHue", + "code": 16384, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EnhancedColorMode", + "code": 16385, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorLoopActive", + "code": 16386, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorLoopDirection", + "code": 16387, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorLoopTime", + "code": 16388, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0019", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorCapabilities", + "code": 16394, + "mfgCode": null, + "side": "server", + "type": "bitmap16", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorTempPhysicalMinMireds", + "code": 16395, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ColorTempPhysicalMaxMireds", + "code": 16396, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFEFF", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CoupleColorTempToLevelMinMireds", + "code": 16397, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "StartUpColorTemperatureMireds", + "code": 16400, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Temperature Measurement", + "code": 1026, + "mfgCode": null, + "define": "TEMPERATURE_MEASUREMENT_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Temperature Measurement", + "code": 1026, + "mfgCode": null, + "define": "TEMPERATURE_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Tolerance", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Relative Humidity Measurement", + "code": 1029, + "mfgCode": null, + "define": "RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Relative Humidity Measurement", + "code": 1029, + "mfgCode": null, + "define": "RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Tolerance", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + } + ] + }, + { + "name": "MA-videoplayer", + "deviceTypeName": "MA-onofflight", + "deviceTypeCode": 256, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "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": "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": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Groups", + "code": 4, + "mfgCode": null, + "define": "GROUPS_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "AddGroup", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "ViewGroup", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GetGroupMembership", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "RemoveGroup", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "RemoveAllGroups", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "AddGroupIfIdentifying", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Groups", + "code": 4, + "mfgCode": null, + "define": "GROUPS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AddGroupResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "ViewGroupResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "GetGroupMembershipResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "RemoveGroupResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "NameSupport", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "NameSupportBitmap", + "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": "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": "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": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Scenes", + "code": 5, + "mfgCode": null, + "define": "SCENES_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "AddScene", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ViewScene", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveScene", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveAllScenes", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StoreScene", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RecallScene", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetSceneMembership", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Scenes", + "code": 5, + "mfgCode": null, + "define": "SCENES_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AddSceneResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ViewSceneResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveSceneResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RemoveAllScenesResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StoreSceneResponse", + "code": 4, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GetSceneMembershipResponse", + "code": 6, + "mfgCode": null, + "source": "server", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "SceneCount", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentScene", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentGroup", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "group_id", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SceneValid", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NameSupport", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConfiguredBy", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "node_id", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SceneTableSize", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RemainingCapacity", + "code": 7, + "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": 0, + "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": 0, + "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": 0, + "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": "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": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "Off", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "On", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "Toggle", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "OffWithEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "OnWithRecallGlobalScene", + "code": 65, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "OnWithTimedOff", + "code": 66, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "OnOff", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 0, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GlobalSceneControl", + "code": 16384, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnTime", + "code": 16385, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OffWaitTime", + "code": 16386, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartUpOnOff", + "code": 16387, + "mfgCode": null, + "side": "server", + "type": "OnOffStartUpOnOff", + "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": "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": "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": "5", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "MoveToLevel", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Move", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Step", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Stop", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "MoveToLevelWithOnOff", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "MoveWithOnOff", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "StepWithOnOff", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "StopWithOnOff", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "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": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Level Control", + "code": 8, + "mfgCode": null, + "define": "LEVEL_CONTROL_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "CurrentLevel", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RemainingTime", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinLevel", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxLevel", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFE", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentFrequency", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinFrequency", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxFrequency", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Options", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "LevelControlOptions", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnOffTransitionTime", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnLevel", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OnTransitionTime", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OffTransitionTime", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "DefaultMoveRate", + "code": 20, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartUpCurrentLevel", + "code": 16384, + "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": "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": 0, + "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": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "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": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": "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": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Binding", + "code": 30, + "mfgCode": null, + "define": "BINDING_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Binding", + "code": 30, + "mfgCode": null, + "define": "BINDING_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "Binding", + "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": "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": "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": "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 + } + ] + }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "Status", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerSourceStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Order", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Description", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredAssessedInputVoltage", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredAssessedInputFrequency", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredCurrentType", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "WiredCurrentTypeEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredAssessedCurrent", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredNominalVoltage", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredMaximumCurrent", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredPresent", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveWiredFaults", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatVoltage", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPercentRemaining", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatTimeRemaining", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatChargeLevel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "BatChargeLevelEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementNeeded", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplaceability", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "BatReplaceabilityEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPresent", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveBatFaults", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementDescription", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatCommonDesignation", + "code": 20, + "mfgCode": null, + "side": "server", + "type": "BatCommonDesignationEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatANSIDesignation", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatIECDesignation", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatApprovedChemistry", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "BatApprovedChemistryEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatCapacity", + "code": 24, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatQuantity", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatChargeState", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "BatChargeStateEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatTimeToFullCharge", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatFunctionalWhileCharging", + "code": 28, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatChargingCurrent", + "code": 29, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveBatChargeFaults", + "code": 30, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "storageOption": "External", + "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": "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": "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 + } + ] + }, + { + "name": "Boolean State", + "code": 69, + "mfgCode": null, + "define": "BOOLEAN_STATE_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Boolean State", + "code": 69, + "mfgCode": null, + "define": "BOOLEAN_STATE_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "StateValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "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": "", + "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": "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": "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 + } + ] + }, + { + "name": "Door Lock", + "code": 257, + "mfgCode": null, + "define": "DOOR_LOCK_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "LockDoor", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "UnlockDoor", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "UnlockWithTimeout", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "SetWeekDaySchedule", + "code": 11, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GetWeekDaySchedule", + "code": 12, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "ClearWeekDaySchedule", + "code": 13, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "SetYearDaySchedule", + "code": 14, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GetYearDaySchedule", + "code": 15, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "ClearYearDaySchedule", + "code": 16, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "SetUser", + "code": 26, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GetUser", + "code": 27, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "ClearUser", + "code": 29, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "SetCredential", + "code": 34, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GetCredentialStatus", + "code": 36, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "ClearCredential", + "code": 38, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ] + }, + { + "name": "Door Lock", + "code": 257, + "mfgCode": null, + "define": "DOOR_LOCK_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "GetWeekDayScheduleResponse", + "code": 12, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "GetYearDayScheduleResponse", + "code": 15, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "GetUserResponse", + "code": 28, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "SetCredentialResponse", + "code": 35, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + }, + { + "name": "GetCredentialStatusResponse", + "code": 37, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "LockState", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "DlLockState", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LockType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "DlLockType", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActuatorEnabled", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "DoorState", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "DoorStateEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfTotalUsersSupported", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfPINUsersSupported", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfRFIDUsersSupported", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfWeekDaySchedulesSupportedPerUser", + "code": 20, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfYearDaySchedulesSupportedPerUser", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxPINCodeLength", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "8", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinPINCodeLength", + "code": 24, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxRFIDCodeLength", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "20", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinRFIDCodeLength", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CredentialRulesSupport", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "DlCredentialRuleMask", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Language", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "en", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LEDSettings", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AutoRelockTime", + "code": 35, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "60", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoundVolume", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OperatingMode", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "OperatingModeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedOperatingModes", + "code": 38, + "mfgCode": null, + "side": "server", + "type": "DlSupportedOperatingModes", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFFF6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EnableOneTouchLocking", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EnablePrivacyModeButton", + "code": 43, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WrongCodeEntryLimit", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UserCodeTemporaryDisableTime", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "10", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RequirePINforRemoteOperation", + "code": 51, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "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": "0x193", + "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": "6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Window Covering", + "code": 258, + "mfgCode": null, + "define": "WINDOW_COVERING_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "UpOrOpen", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "DownOrClose", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StopMotion", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "GoToLiftValue", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GoToLiftPercentage", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GoToTiltValue", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "GoToTiltPercentage", + "code": 8, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Window Covering", + "code": 258, + "mfgCode": null, + "define": "WINDOW_COVERING_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "Type", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "Type", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PhysicalClosedLimitLift", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PhysicalClosedLimitTilt", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPositionLift", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPositionTilt", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfActuationsLift", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfActuationsTilt", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ConfigStatus", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "ConfigStatus", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPositionLiftPercentage", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "Percent", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPositionTiltPercentage", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "Percent", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OperationalStatus", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "OperationalStatus", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0C", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetPositionLiftPercent100ths", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "Percent100ths", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetPositionTiltPercent100ths", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "Percent100ths", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EndProductType", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "EndProductType", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPositionLiftPercent100ths", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "Percent100ths", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPositionTiltPercent100ths", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "Percent100ths", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InstalledOpenLimitLift", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InstalledClosedLimitLift", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFFFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InstalledOpenLimitTilt", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InstalledClosedLimitTilt", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFFFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Mode", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "Mode", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SafetyStatus", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "SafetyStatus", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "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": "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": "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": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat", + "code": 513, + "mfgCode": null, + "define": "THERMOSTAT_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "SetpointRaiseLower", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat", + "code": 513, + "mfgCode": null, + "define": "THERMOSTAT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "LocalTemperature", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OutdoorTemperature", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Occupancy", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMinHeatSetpointLimit", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "700", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMaxHeatSetpointLimit", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMinCoolSetpointLimit", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1600", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMaxCoolSetpointLimit", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3200", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PICoolingDemand", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PIHeatingDemand", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HVACSystemTypeConfiguration", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocalTemperatureCalibration", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int8s", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupiedCoolingSetpoint", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2600", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupiedHeatingSetpoint", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UnoccupiedCoolingSetpoint", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2600", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UnoccupiedHeatingSetpoint", + "code": 20, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinHeatSetpointLimit", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "700", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxHeatSetpointLimit", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinCoolSetpointLimit", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1600", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxCoolSetpointLimit", + "code": 24, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3200", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinSetpointDeadBand", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int8s", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "25", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RemoteSensing", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ControlSequenceOfOperation", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "ThermostatControlSequence", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x04", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SystemMode", + "code": 28, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThermostatRunningMode", + "code": 30, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartOfWeek", + "code": 32, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfWeeklyTransitions", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfDailyTransitions", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TemperatureSetpointHold", + "code": 35, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TemperatureSetpointHoldDuration", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFFFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThermostatProgrammingOperationMode", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThermostatRunningState", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "bitmap16", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SetpointChangeSource", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SetpointChangeAmount", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SetpointChangeSourceTimestamp", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "epoch_s", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupiedSetback", + "code": 52, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupiedSetbackMin", + "code": 53, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupiedSetbackMax", + "code": 54, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UnoccupiedSetback", + "code": 55, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UnoccupiedSetbackMin", + "code": 56, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UnoccupiedSetbackMax", + "code": 57, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EmergencyHeatDelta", + "code": 58, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACType", + "code": 64, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACCapacity", + "code": 65, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACRefrigerantType", + "code": 66, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACCompressorType", + "code": 67, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACErrorCode", + "code": 68, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACLouverPosition", + "code": 69, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACCoilTemperature", + "code": 70, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ACCapacityformat", + "code": 71, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "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": "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": "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": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Fan Control", + "code": 514, + "mfgCode": null, + "define": "FAN_CONTROL_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Fan Control", + "code": 514, + "mfgCode": null, + "define": "FAN_CONTROL_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "FanMode", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "FanModeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FanModeSequence", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "FanModeSequenceEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PercentSetting", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "Percent", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PercentCurrent", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "Percent", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpeedMax", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpeedSetting", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpeedCurrent", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RockSupport", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "RockBitmap", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RockSetting", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "RockBitmap", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WindSupport", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "WindBitmap", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WindSetting", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "WindBitmap", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "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": "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": "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 + } + ] + }, + { + "name": "Color Control", + "code": 768, + "mfgCode": null, + "define": "COLOR_CONTROL_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "MoveToHue", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "MoveToSaturation", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "MoveToHueAndSaturation", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "MoveToColor", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "MoveToColorTemperature", + "code": 10, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Color Control", + "code": 768, + "mfgCode": null, + "define": "COLOR_CONTROL_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "CurrentHue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentSaturation", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RemainingTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentX", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x616B", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentY", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x607D", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "DriftCompensation", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CompensationText", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorTemperatureMireds", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00FA", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorMode", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Options", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "bitmap8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfPrimaries", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary1X", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary1Y", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary1Intensity", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary2X", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary2Y", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary2Intensity", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary3X", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary3Y", + "code": 26, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary3Intensity", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary4X", + "code": 32, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary4Y", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary4Intensity", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary5X", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary5Y", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary5Intensity", + "code": 38, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary6X", + "code": 40, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary6Y", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Primary6Intensity", + "code": 42, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WhitePointX", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WhitePointY", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointRX", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointRY", + "code": 51, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointRIntensity", + "code": 52, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointGX", + "code": 54, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointGY", + "code": 55, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointGIntensity", + "code": 56, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointBX", + "code": 58, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointBY", + "code": 59, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorPointBIntensity", + "code": 60, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EnhancedCurrentHue", + "code": 16384, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EnhancedColorMode", + "code": 16385, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorLoopActive", + "code": 16386, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorLoopDirection", + "code": 16387, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorLoopTime", + "code": 16388, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0019", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorLoopStartEnhancedHue", + "code": 16389, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x2300", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorLoopStoredEnhancedHue", + "code": 16390, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorCapabilities", + "code": 16394, + "mfgCode": null, + "side": "server", + "type": "bitmap16", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorTempPhysicalMinMireds", + "code": 16395, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ColorTempPhysicalMaxMireds", + "code": 16396, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFEFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CoupleColorTempToLevelMinMireds", + "code": 16397, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartUpColorTemperatureMireds", + "code": 16400, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "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": "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": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "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": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Illuminance Measurement", + "code": 1024, + "mfgCode": null, + "define": "ILLUMINANCE_MEASUREMENT_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Illuminance Measurement", + "code": 1024, + "mfgCode": null, + "define": "ILLUMINANCE_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Tolerance", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LightSensorType", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "LightSensorTypeEnum", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFF", + "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": "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": "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": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Temperature Measurement", + "code": 1026, + "mfgCode": null, + "define": "TEMPERATURE_MEASUREMENT_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Temperature Measurement", + "code": 1026, + "mfgCode": null, + "define": "TEMPERATURE_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x8000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Tolerance", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "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": "", + "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": "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": "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 + } + ] + }, + { + "name": "Relative Humidity Measurement", + "code": 1029, + "mfgCode": null, + "define": "RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "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": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Relative Humidity Measurement", + "code": 1029, + "mfgCode": null, + "define": "RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Tolerance", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "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": "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": "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": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Occupancy Sensing", + "code": 1030, + "mfgCode": null, + "define": "OCCUPANCY_SENSING_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "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": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Occupancy Sensing", + "code": 1030, + "mfgCode": null, + "define": "OCCUPANCY_SENSING_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "Occupancy", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "OccupancyBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupancySensorType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "OccupancySensorTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupancySensorTypeBitmap", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "OccupancySensorTypeBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PIROccupiedToUnoccupiedDelay", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PIRUnoccupiedToOccupiedDelay", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PIRUnoccupiedToOccupiedThreshold", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UltrasonicOccupiedToUnoccupiedDelay", + "code": 32, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UltrasonicUnoccupiedToOccupiedDelay", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UltrasonicUnoccupiedToOccupiedThreshold", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PhysicalContactOccupiedToUnoccupiedDelay", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PhysicalContactUnoccupiedToOccupiedDelay", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PhysicalContactUnoccupiedToOccupiedThreshold", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "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": "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": 0, + "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": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Wake on LAN", + "code": 1283, + "mfgCode": null, + "define": "WAKE_ON_LAN_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Wake on LAN", + "code": 1283, + "mfgCode": null, + "define": "WAKE_ON_LAN_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "MACAddress", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Channel", + "code": 1284, + "mfgCode": null, + "define": "CHANNEL_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "ChangeChannel", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ChangeChannelByNumber", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "SkipChannel", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Channel", + "code": 1284, + "mfgCode": null, + "define": "CHANNEL_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "ChangeChannelResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ChannelList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Lineup", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "LineupInfoStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentChannel", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "ChannelInfoStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "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": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Target Navigator", + "code": 1285, + "mfgCode": null, + "define": "TARGET_NAVIGATOR_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "NavigateTarget", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Target Navigator", + "code": 1285, + "mfgCode": null, + "define": "TARGET_NAVIGATOR_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "NavigateTargetResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "TargetList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentTarget", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "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": 0, + "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": 0, + "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": 0, + "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": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Media Playback", + "code": 1286, + "mfgCode": null, + "define": "MEDIA_PLAYBACK_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "Play", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Pause", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Stop", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "StartOver", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Previous", + "code": 4, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Next", + "code": 5, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Rewind", + "code": 6, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "FastForward", + "code": 7, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "SkipForward", + "code": 8, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "SkipBackward", + "code": 9, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Seek", + "code": 11, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ] + }, + { + "name": "Media Playback", + "code": 1286, + "mfgCode": null, + "define": "MEDIA_PLAYBACK_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "PlaybackResponse", + "code": 10, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "CurrentState", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PlaybackStateEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StartTime", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "epoch_us", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Duration", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SampledPosition", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "PlaybackPositionStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PlaybackSpeed", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "single", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SeekRangeEnd", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SeekRangeStart", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "int64u", + "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": "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": "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 + } + ] + }, + { + "name": "Media Input", + "code": 1287, + "mfgCode": null, + "define": "MEDIA_INPUT_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "SelectInput", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "ShowInputStatus", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "HideInputStatus", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "RenameInput", + "code": 3, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Media Input", + "code": 1287, + "mfgCode": null, + "define": "MEDIA_INPUT_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "InputList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentInput", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "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": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Low Power", + "code": 1288, + "mfgCode": null, + "define": "LOW_POWER_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "Sleep", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Low Power", + "code": 1288, + "mfgCode": null, + "define": "LOW_POWER_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Keypad Input", + "code": 1289, + "mfgCode": null, + "define": "KEYPAD_INPUT_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "SendKey", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Keypad Input", + "code": 1289, + "mfgCode": null, + "define": "KEYPAD_INPUT_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "SendKeyResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "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": "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Content Launcher", + "code": 1290, + "mfgCode": null, + "define": "CONTENT_LAUNCHER_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "LaunchContent", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "LaunchURL", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Content Launcher", + "code": 1290, + "mfgCode": null, + "define": "CONTENT_LAUNCHER_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "LauncherResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "AcceptHeader", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SupportedStreamingProtocols", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Application Launcher", + "code": 1292, + "mfgCode": null, + "define": "APPLICATION_LAUNCHER_CLUSTER", + "side": "client", + "enabled": 0, + "commands": [ + { + "name": "LaunchApp", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 1 + }, + { + "name": "StopApp", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "HideApp", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], + "attributes": [ + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Application Launcher", + "code": 1292, + "mfgCode": null, + "define": "APPLICATION_LAUNCHER_CLUSTER", + "side": "server", + "enabled": 0, + "commands": [ + { + "name": "LauncherResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "incoming": 0, + "outgoing": 1 + } + ], + "attributes": [ + { + "name": "CatalogList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentApp", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "ApplicationEPStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "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": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "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": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Application Basic", + "code": 1293, + "mfgCode": null, + "define": "APPLICATION_BASIC_CLUSTER", + "side": "client", + "enabled": 0 + }, + { + "name": "Application Basic", + "code": 1293, + "mfgCode": null, + "define": "APPLICATION_BASIC_CLUSTER", + "side": "server", + "enabled": 0, + "attributes": [ + { + "name": "VendorName", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ApplicationName", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Application", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "ApplicationStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Status", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "ApplicationStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ApplicationVersion", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AllowedVendorList", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 0, + "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": 0, + "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": 0, + "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": 0, + "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 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0, + "endpointVersion": 1, + "deviceIdentifier": 22 + }, + { + "endpointTypeName": "MA-videoplayer", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0, + "endpointVersion": 1, + "deviceIdentifier": 256 + } + ], + "log": [] +} \ No newline at end of file diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 91bf326e2933e2..877d98564de512 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -328,6 +328,8 @@ def BuildAndroidTarget(): TargetPart('tv-casting-app', app=AndroidApp.TV_CASTING_APP), TargetPart('java-matter-controller', app=AndroidApp.JAVA_MATTER_CONTROLLER), + TargetPart('virtual-device-app', + app=AndroidApp.VIRTUAL_DEVICE_APP), ]) # Modifiers diff --git a/scripts/build/builders/android.py b/scripts/build/builders/android.py index 3ae81c9f8e8b09..cd358798c218fc 100644 --- a/scripts/build/builders/android.py +++ b/scripts/build/builders/android.py @@ -71,6 +71,7 @@ class AndroidApp(Enum): TV_SERVER = auto() TV_CASTING_APP = auto() JAVA_MATTER_CONTROLLER = auto() + VIRTUAL_DEVICE_APP = auto() def AppName(self): if self == AndroidApp.CHIP_TOOL: @@ -81,6 +82,8 @@ def AppName(self): return "tv-server" elif self == AndroidApp.TV_CASTING_APP: return "tv-casting" + elif self == AndroidApp.VIRTUAL_DEVICE_APP: + return "virtual-device-app" else: raise Exception("Unknown app type: %r" % self) @@ -91,6 +94,8 @@ def AppGnArgs(self): gn_args["chip_config_network_layer_ble"] = False elif self == AndroidApp.TV_CASTING_APP: gn_args["chip_config_network_layer_ble"] = False + elif self == AndroidApp.VIRTUAL_DEVICE_APP: + gn_args["chip_config_network_layer_ble"] = True return gn_args def ExampleName(self): @@ -98,6 +103,8 @@ def ExampleName(self): return "tv-app" elif self == AndroidApp.TV_CASTING_APP: return "tv-casting-app" + elif self == AndroidApp.VIRTUAL_DEVICE_APP: + return "virtual-device-app" else: return None @@ -484,6 +491,30 @@ def _build(self): "TvApp.jar": "TvApp.jar", } + self.copyToExampleApp(jnilibs_dir, libs_dir, libs, jars) + self.gradlewBuildExampleAndroid() + elif exampleName == "virtual-device-app": + jnilibs_dir = os.path.join( + self.root, + "examples/", + self.app.ExampleName(), + "android/App/app/libs/jniLibs", + self.board.AbiName(), + ) + + libs_dir = os.path.join( + self.root, "examples/", self.app.ExampleName(), "android/App/app/libs" + ) + + libs = ["libc++_shared.so", "libDeviceApp.so"] + + jars = { + "OnboardingPayload.jar": "third_party/connectedhomeip/src/controller/java/OnboardingPayload.jar", + "AndroidPlatform.jar": "third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar", + "CHIPAppServer.jar": "third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar", + "DeviceApp.jar": "DeviceApp.jar", + } + self.copyToExampleApp(jnilibs_dir, libs_dir, libs, jars) self.gradlewBuildExampleAndroid() @@ -511,6 +542,12 @@ def build_outputs(self): self.output_dir, "content-app", "outputs", "apk", "debug", "content-app-debug.apk" ) } + elif self.app == AndroidApp.VIRTUAL_DEVICE_APP: + outputs = { + self.app.AppName() + "app-debug.apk": os.path.join( + self.output_dir, "VirtualDeviceApp", "app", "outputs", "apk", "debug", "app-debug.apk" + ) + } else: outputs = { self.app.AppName() + "app-debug.apk": os.path.join( diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index 5d0c6c300018db..05f8fd0a1340b5 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -1,6 +1,6 @@ ameba-amebad-{all-clusters,all-clusters-minimal,light,light-switch,pigweed} asr-{asr582x,asr595x,asr550x}-{all-clusters,all-clusters-minimal,lighting,light-switch,lock,bridge,temperature-measurement,thermostat,ota-requestor}[-ota][-shell][-no_logging][-factory][-rotating_id][-rio] -android-{arm,arm64,x86,x64,androidstudio-arm,androidstudio-arm64,androidstudio-x86,androidstudio-x64}-{chip-tool,chip-test,tv-server,tv-casting-app,java-matter-controller}[-no-debug] +android-{arm,arm64,x86,x64,androidstudio-arm,androidstudio-arm64,androidstudio-x86,androidstudio-x64}-{chip-tool,chip-test,tv-server,tv-casting-app,java-matter-controller,virtual-device-app}[-no-debug] bouffalolab-{bl602-iot-matter-v1,bl602-night-light,xt-zb6-devkit,bl706-night-light,bl706-eth,bl704l-dvk}-light[-shell][-115200][-rpc][-cdc][-resetcnt][-rotating_device_id] cc32xx-lock ti-cc13x2x7_26x2x7-{lighting,lock,pump,pump-controller}[-mtd]